|
30 | 30 | import org.springframework.data.elasticsearch.annotations.GeoShapeField;
|
31 | 31 | import org.springframework.data.elasticsearch.annotations.MultiField;
|
32 | 32 | import org.springframework.data.elasticsearch.core.completion.Completion;
|
33 |
| -import org.springframework.data.elasticsearch.core.convert.ConversionException; |
| 33 | +import org.springframework.data.elasticsearch.core.convert.DatePersistentPropertyConverter; |
34 | 34 | import org.springframework.data.elasticsearch.core.convert.ElasticsearchDateConverter;
|
| 35 | +import org.springframework.data.elasticsearch.core.convert.TemporalPersistentPropertyConverter; |
35 | 36 | import org.springframework.data.elasticsearch.core.geo.GeoJson;
|
36 | 37 | import org.springframework.data.elasticsearch.core.geo.GeoPoint;
|
37 | 38 | import org.springframework.data.elasticsearch.core.join.JoinField;
|
38 | 39 | import org.springframework.data.elasticsearch.core.query.SeqNoPrimaryTerm;
|
39 | 40 | import org.springframework.data.mapping.Association;
|
40 | 41 | import org.springframework.data.mapping.MappingException;
|
41 | 42 | import org.springframework.data.mapping.PersistentEntity;
|
| 43 | +import org.springframework.data.mapping.PersistentProperty; |
42 | 44 | import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
|
43 | 45 | import org.springframework.data.mapping.model.FieldNamingStrategy;
|
44 | 46 | import org.springframework.data.mapping.model.Property;
|
@@ -128,102 +130,76 @@ protected boolean hasExplicitFieldName() {
|
128 | 130 | }
|
129 | 131 |
|
130 | 132 | /**
|
131 |
| - * Initializes an {@link ElasticsearchPersistentPropertyConverter} if this property is annotated as a Field with type |
132 |
| - * {@link FieldType#Date}, has a {@link DateFormat} set and if the type of the property is one of the Java8 temporal |
133 |
| - * classes or java.util.Date. |
| 133 | + * Set the property converter for this {@link PersistentProperty} to {@link TemporalPersistentPropertyConverter} or |
| 134 | + * {@link DatePersistentPropertyConverter} depending on the property type and if the property is annotated with |
| 135 | + * {@code @Field} of type {@link FieldType#Date} or {@link FieldType#Date_Nanos}. |
134 | 136 | */
|
135 | 137 | private void initDateConverter() {
|
136 |
| - Field field = findAnnotation(Field.class); |
137 |
| - |
138 |
| - Class<?> actualType = getActualTypeOrNull(); |
139 | 138 |
|
140 |
| - if (actualType == null) { |
| 139 | + if (!isDateProperty()) { |
141 | 140 | return;
|
142 | 141 | }
|
143 | 142 |
|
144 |
| - boolean isTemporalAccessor = TemporalAccessor.class.isAssignableFrom(actualType); |
145 |
| - boolean isDate = Date.class.isAssignableFrom(actualType); |
| 143 | + Class<?> actualType = getActualType(); |
| 144 | + List<ElasticsearchDateConverter> dateConverters = getDateConverters(); |
146 | 145 |
|
147 |
| - if (field != null && (field.type() == FieldType.Date || field.type() == FieldType.Date_Nanos) |
148 |
| - && (isTemporalAccessor || isDate)) { |
149 |
| - |
150 |
| - DateFormat[] dateFormats = field.format(); |
151 |
| - String[] dateFormatPatterns = field.pattern(); |
| 146 | + if (dateConverters.isEmpty()) { |
| 147 | + LOGGER.warn("No date formatters configured for property '{}'.", getName()); |
| 148 | + return; |
| 149 | + } |
152 | 150 |
|
153 |
| - String property = getOwner().getType().getSimpleName() + "." + getName(); |
| 151 | + if (TemporalAccessor.class.isAssignableFrom(actualType)) { |
| 152 | + propertyConverter = new TemporalPersistentPropertyConverter(this, dateConverters); |
| 153 | + } else if (Date.class.isAssignableFrom(actualType)) { |
| 154 | + propertyConverter = new DatePersistentPropertyConverter(this, dateConverters); |
| 155 | + } else { |
| 156 | + LOGGER.warn("Unsupported type '{}' for date property '{}'.", actualType, getName()); |
| 157 | + } |
| 158 | + } |
154 | 159 |
|
155 |
| - if (dateFormats.length == 0 && dateFormatPatterns.length == 0) { |
156 |
| - LOGGER.warn( |
157 |
| - "Property '{}' has @Field type '{}' but has no built-in format or custom date pattern defined. Make sure you have a converter registered for type {}.", |
158 |
| - property, field.type().name(), actualType.getSimpleName()); |
159 |
| - return; |
160 |
| - } |
| 160 | + private List<ElasticsearchDateConverter> getDateConverters() { |
161 | 161 |
|
162 |
| - List<ElasticsearchDateConverter> converters = new ArrayList<>(); |
163 |
| - |
164 |
| - // register converters for built-in formats |
165 |
| - for (DateFormat dateFormat : dateFormats) { |
166 |
| - switch (dateFormat) { |
167 |
| - case none: |
168 |
| - case custom: |
169 |
| - break; |
170 |
| - case weekyear: |
171 |
| - case weekyear_week: |
172 |
| - case weekyear_week_day: |
173 |
| - LOGGER.warn("No default converter available for '{}' and date format '{}'. Use a custom converter instead.", |
174 |
| - actualType.getName(), dateFormat.name()); |
175 |
| - break; |
176 |
| - default: |
177 |
| - converters.add(ElasticsearchDateConverter.of(dateFormat)); |
178 |
| - break; |
179 |
| - } |
180 |
| - } |
| 162 | + Field field = findAnnotation(Field.class); |
| 163 | + DateFormat[] dateFormats = field.format(); |
| 164 | + String[] dateFormatPatterns = field.pattern(); |
| 165 | + String property = getOwner().getType().getSimpleName() + "." + getName(); |
| 166 | + Class<?> actualType = getActualType(); |
| 167 | + List<ElasticsearchDateConverter> converters = new ArrayList<>(); |
| 168 | + |
| 169 | + if (dateFormats.length == 0 && dateFormatPatterns.length == 0) { |
| 170 | + LOGGER.warn( |
| 171 | + "Property '{}' has @Field type '{}' but has no built-in format or custom date pattern defined. Make sure you have a converter registered for type {}.", |
| 172 | + property, field.type().name(), actualType.getSimpleName()); |
| 173 | + return converters; |
| 174 | + } |
181 | 175 |
|
182 |
| - // register converters for custom formats |
183 |
| - for (String dateFormatPattern : dateFormatPatterns) { |
184 |
| - if (!StringUtils.hasText(dateFormatPattern)) { |
185 |
| - throw new MappingException(String.format("Date pattern of property '%s' must not be empty", property)); |
186 |
| - } |
187 |
| - converters.add(ElasticsearchDateConverter.of(dateFormatPattern)); |
| 176 | + // register converters for built-in formats |
| 177 | + for (DateFormat dateFormat : dateFormats) { |
| 178 | + switch (dateFormat) { |
| 179 | + case none: |
| 180 | + case custom: |
| 181 | + break; |
| 182 | + case weekyear: |
| 183 | + case weekyear_week: |
| 184 | + case weekyear_week_day: |
| 185 | + LOGGER.warn("No default converter available for '{}' and date format '{}'. Use a custom converter instead.", |
| 186 | + actualType.getName(), dateFormat.name()); |
| 187 | + break; |
| 188 | + default: |
| 189 | + converters.add(ElasticsearchDateConverter.of(dateFormat)); |
| 190 | + break; |
188 | 191 | }
|
| 192 | + } |
189 | 193 |
|
190 |
| - if (!converters.isEmpty()) { |
191 |
| - propertyConverter = new ElasticsearchPersistentPropertyConverter() { |
192 |
| - final List<ElasticsearchDateConverter> dateConverters = converters; |
193 |
| - |
194 |
| - @SuppressWarnings("unchecked") |
195 |
| - @Override |
196 |
| - public Object read(String s) { |
197 |
| - for (ElasticsearchDateConverter dateConverter : dateConverters) { |
198 |
| - try { |
199 |
| - if (isTemporalAccessor) { |
200 |
| - return dateConverter.parse(s, (Class<? extends TemporalAccessor>) actualType); |
201 |
| - } else { // must be date |
202 |
| - return dateConverter.parse(s); |
203 |
| - } |
204 |
| - } catch (Exception e) { |
205 |
| - LOGGER.trace(e.getMessage(), e); |
206 |
| - } |
207 |
| - } |
208 |
| - |
209 |
| - throw new ConversionException(String |
210 |
| - .format("Unable to parse date value '%s' of property '%s' with configured converters", s, property)); |
211 |
| - } |
212 |
| - |
213 |
| - @Override |
214 |
| - public String write(Object property) { |
215 |
| - ElasticsearchDateConverter dateConverter = dateConverters.get(0); |
216 |
| - if (isTemporalAccessor && TemporalAccessor.class.isAssignableFrom(property.getClass())) { |
217 |
| - return dateConverter.format((TemporalAccessor) property); |
218 |
| - } else if (isDate && Date.class.isAssignableFrom(property.getClass())) { |
219 |
| - return dateConverter.format((Date) property); |
220 |
| - } else { |
221 |
| - return property.toString(); |
222 |
| - } |
223 |
| - } |
224 |
| - }; |
| 194 | + // register converters for custom formats |
| 195 | + for (String dateFormatPattern : dateFormatPatterns) { |
| 196 | + if (!StringUtils.hasText(dateFormatPattern)) { |
| 197 | + throw new MappingException(String.format("Date pattern of property '%s' must not be empty", property)); |
225 | 198 | }
|
| 199 | + converters.add(ElasticsearchDateConverter.of(dateFormatPattern)); |
226 | 200 | }
|
| 201 | + |
| 202 | + return converters; |
227 | 203 | }
|
228 | 204 |
|
229 | 205 | @SuppressWarnings("ConstantConditions")
|
@@ -303,4 +279,21 @@ public boolean isJoinFieldProperty() {
|
303 | 279 | public boolean isCompletionProperty() {
|
304 | 280 | return getActualType() == Completion.class;
|
305 | 281 | }
|
| 282 | + |
| 283 | + private boolean isDateProperty() { |
| 284 | + |
| 285 | + Class<?> actualType = getActualTypeOrNull(); |
| 286 | + if (actualType == null |
| 287 | + || !Date.class.isAssignableFrom(actualType) && !TemporalAccessor.class.isAssignableFrom(actualType)) { |
| 288 | + return false; |
| 289 | + } |
| 290 | + |
| 291 | + Field field = findAnnotation(Field.class); |
| 292 | + if (field == null || field.type() == null) { |
| 293 | + return false; |
| 294 | + } |
| 295 | + |
| 296 | + return field.type() == FieldType.Date || field.type() == FieldType.Date_Nanos; |
| 297 | + } |
| 298 | + |
306 | 299 | }
|
0 commit comments