@@ -168,8 +168,15 @@ public void afterPropertiesSet() {
168
168
@ SuppressWarnings ("unchecked" )
169
169
@ Override
170
170
public <R > R read (Class <R > type , Document source ) {
171
+
171
172
TypeInformation <R > typeHint = ClassTypeInformation .from ((Class <R >) ClassUtils .getUserClass (type ));
172
- return read (typeHint , source );
173
+ R r = read (typeHint , source );
174
+
175
+ if (r == null ) {
176
+ throw new ConversionException ("could not convert into object of class " + type );
177
+ }
178
+
179
+ return r ;
173
180
}
174
181
175
182
protected <R > R readEntity (ElasticsearchPersistentEntity <?> entity , Map <String , Object > source ) {
@@ -188,7 +195,7 @@ protected <R> R readEntity(ElasticsearchPersistentEntity<?> entity, Map<String,
188
195
189
196
EntityInstantiator instantiator = instantiators .getInstantiatorFor (targetEntity );
190
197
191
- @ SuppressWarnings ({ "unchecked" , "ConstantConditions" })
198
+ @ SuppressWarnings ({ "unchecked" })
192
199
R instance = (R ) instantiator .createInstance (targetEntity , propertyValueProvider );
193
200
194
201
if (!targetEntity .requiresPropertyPopulation ()) {
@@ -246,6 +253,7 @@ private ParameterValueProvider<ElasticsearchPersistentProperty> getParameterProv
246
253
ElasticsearchPropertyValueProvider provider = new ElasticsearchPropertyValueProvider (source , evaluator );
247
254
248
255
// TODO: Support for non-static inner classes via ObjectPath
256
+ // noinspection ConstantConditions
249
257
PersistentEntityParameterValueProvider <ElasticsearchPersistentProperty > parameterProvider = new PersistentEntityParameterValueProvider <>(
250
258
entity , provider , null );
251
259
@@ -281,7 +289,6 @@ protected <R> R readProperties(ElasticsearchPersistentEntity<?> entity, R instan
281
289
return accessor .getBean ();
282
290
}
283
291
284
- @ SuppressWarnings ("unchecked" )
285
292
@ Nullable
286
293
protected <R > R readValue (@ Nullable Object value , ElasticsearchPersistentProperty property , TypeInformation <?> type ) {
287
294
@@ -349,7 +356,7 @@ private <R> R read(TypeInformation<R> type, Map<String, Object> source) {
349
356
}
350
357
351
358
if (typeToUse .isMap ()) {
352
- return ( R ) readMap (typeToUse , source );
359
+ return readMap (typeToUse , source );
353
360
}
354
361
355
362
if (typeToUse .equals (ClassTypeInformation .OBJECT )) {
@@ -549,7 +556,7 @@ public void write(Object source, Document sink) {
549
556
}
550
557
551
558
Class <?> entityType = ClassUtils .getUserClass (source .getClass ());
552
- TypeInformation <? extends Object > typeInformation = ClassTypeInformation .from (entityType );
559
+ TypeInformation <?> typeInformation = ClassTypeInformation .from (entityType );
553
560
554
561
if (requiresTypeHint (entityType )) {
555
562
typeMapper .writeType (typeInformation , sink );
@@ -561,9 +568,9 @@ public void write(Object source, Document sink) {
561
568
/**
562
569
* Internal write conversion method which should be used for nested invocations.
563
570
*
564
- * @param source
565
- * @param sink
566
- * @param typeInformation
571
+ * @param source the object to write
572
+ * @param sink the write destination
573
+ * @param typeInformation type information for the source
567
574
*/
568
575
@ SuppressWarnings ("unchecked" )
569
576
protected void writeInternal (@ Nullable Object source , Map <String , Object > sink ,
@@ -578,7 +585,10 @@ protected void writeInternal(@Nullable Object source, Map<String, Object> sink,
578
585
579
586
if (customTarget .isPresent ()) {
580
587
Map <String , Object > result = conversionService .convert (source , Map .class );
581
- sink .putAll (result );
588
+
589
+ if (result != null ) {
590
+ sink .putAll (result );
591
+ }
582
592
return ;
583
593
}
584
594
@@ -600,9 +610,9 @@ protected void writeInternal(@Nullable Object source, Map<String, Object> sink,
600
610
/**
601
611
* Internal write conversion method which should be used for nested invocations.
602
612
*
603
- * @param source
604
- * @param sink
605
- * @param entity
613
+ * @param source the object to write
614
+ * @param sink the write destination
615
+ * @param entity entity for the source
606
616
*/
607
617
protected void writeInternal (@ Nullable Object source , Map <String , Object > sink ,
608
618
@ Nullable ElasticsearchPersistentEntity <?> entity ) {
@@ -734,7 +744,6 @@ protected void writeProperty(ElasticsearchPersistentProperty property, Object va
734
744
*
735
745
* @param collection must not be {@literal null}.
736
746
* @param property must not be {@literal null}.
737
- * @return
738
747
*/
739
748
protected List <Object > createCollection (Collection <?> collection , ElasticsearchPersistentProperty property ) {
740
749
return writeCollectionInternal (collection , property .getTypeInformation (), new ArrayList <>(collection .size ()));
@@ -745,7 +754,6 @@ protected List<Object> createCollection(Collection<?> collection, ElasticsearchP
745
754
*
746
755
* @param map must not {@literal null}.
747
756
* @param property must not be {@literal null}.
748
- * @return
749
757
*/
750
758
protected Map <String , Object > createMap (Map <?, ?> map , ElasticsearchPersistentProperty property ) {
751
759
@@ -761,7 +769,6 @@ protected Map<String, Object> createMap(Map<?, ?> map, ElasticsearchPersistentPr
761
769
* @param source must not be {@literal null}.
762
770
* @param sink must not be {@literal null}.
763
771
* @param propertyType must not be {@literal null}.
764
- * @return
765
772
*/
766
773
protected Map <String , Object > writeMapInternal (Map <?, ?> source , Map <String , Object > sink ,
767
774
TypeInformation <?> propertyType ) {
@@ -801,7 +808,6 @@ protected Map<String, Object> writeMapInternal(Map<?, ?> source, Map<String, Obj
801
808
* @param source the collection to create a {@link Collection} for, must not be {@literal null}.
802
809
* @param type the {@link TypeInformation} to consider or {@literal null} if unknown.
803
810
* @param sink the {@link Collection} to write to.
804
- * @return
805
811
*/
806
812
@ SuppressWarnings ("unchecked" )
807
813
private List <Object > writeCollectionInternal (Collection <?> source , @ Nullable TypeInformation <?> type ,
@@ -837,26 +843,30 @@ private List<Object> writeCollectionInternal(Collection<?> source, @Nullable Typ
837
843
/**
838
844
* Returns a {@link String} representation of the given {@link Map} key
839
845
*
840
- * @param key
841
- * @return
846
+ * @param key the key to convert
842
847
*/
843
848
private String potentiallyConvertMapKey (Object key ) {
844
849
845
850
if (key instanceof String ) {
846
851
return (String ) key ;
847
852
}
848
853
849
- return conversions .hasCustomWriteTarget (key .getClass (), String .class )
850
- ? (String ) getPotentiallyConvertedSimpleWrite (key , Object .class )
851
- : key .toString ();
854
+ if (conversions .hasCustomWriteTarget (key .getClass (), String .class )) {
855
+ Object potentiallyConvertedSimpleWrite = getPotentiallyConvertedSimpleWrite (key , Object .class );
856
+
857
+ if (potentiallyConvertedSimpleWrite == null ) {
858
+ return key .toString ();
859
+ }
860
+ return (String ) potentiallyConvertedSimpleWrite ;
861
+ }
862
+ return key .toString ();
852
863
}
853
864
854
865
/**
855
866
* Checks whether we have a custom conversion registered for the given value into an arbitrary simple Elasticsearch
856
867
* type. Returns the converted value if so. If not, we perform special enum handling or simply return the value as is.
857
868
*
858
- * @param value
859
- * @return
869
+ * @param value value to convert
860
870
*/
861
871
@ Nullable
862
872
private Object getPotentiallyConvertedSimpleWrite (@ Nullable Object value , @ Nullable Class <?> typeHint ) {
@@ -869,6 +879,10 @@ private Object getPotentiallyConvertedSimpleWrite(@Nullable Object value, @Nulla
869
879
870
880
if (conversionService .canConvert (value .getClass (), typeHint )) {
871
881
value = conversionService .convert (value , typeHint );
882
+
883
+ if (value == null ) {
884
+ return null ;
885
+ }
872
886
}
873
887
}
874
888
@@ -908,8 +922,8 @@ protected Object getWriteSimpleValue(Object value) {
908
922
* @deprecated since 4.2, use {@link #writeInternal(Object, Map, TypeInformation)} instead.
909
923
*/
910
924
@ Deprecated
911
- protected Object getWriteComplexValue (ElasticsearchPersistentProperty property , TypeInformation <?> typeHint ,
912
- Object value ) {
925
+ protected Object getWriteComplexValue (ElasticsearchPersistentProperty property ,
926
+ @ SuppressWarnings ( "unused" ) TypeInformation <?> typeHint , Object value ) {
913
927
914
928
Document document = Document .create ();
915
929
writeInternal (value , document , property .getTypeInformation ());
@@ -928,11 +942,19 @@ protected Object getWriteComplexValue(ElasticsearchPersistentProperty property,
928
942
*
929
943
* @param source must not be {@literal null}.
930
944
* @param sink must not be {@literal null}.
931
- * @param type
945
+ * @param type type to compare to
932
946
*/
933
- protected void addCustomTypeKeyIfNecessary (Object source , Map <String , Object > sink , @ Nullable TypeInformation <?> type ) {
947
+ protected void addCustomTypeKeyIfNecessary (Object source , Map <String , Object > sink ,
948
+ @ Nullable TypeInformation <?> type ) {
934
949
935
- Class <?> reference = type != null ? type .getActualType ().getType () : Object .class ;
950
+ Class <?> reference ;
951
+
952
+ if (type == null ) {
953
+ reference = Object .class ;
954
+ } else {
955
+ TypeInformation <?> actualType = type .getActualType ();
956
+ reference = actualType == null ? Object .class : actualType .getType ();
957
+ }
936
958
Class <?> valueType = ClassUtils .getUserClass (source .getClass ());
937
959
938
960
boolean notTheSameClass = !valueType .equals (reference );
@@ -987,8 +1009,7 @@ private boolean isSimpleType(Class<?> type) {
987
1009
* {@link Collection} already, will convert an array into a {@link Collection} or simply create a single element
988
1010
* collection for everything else.
989
1011
*
990
- * @param source
991
- * @return
1012
+ * @param source object to convert
992
1013
*/
993
1014
private static Collection <?> asCollection (Object source ) {
994
1015
@@ -1019,21 +1040,42 @@ public void updateCriteriaQuery(CriteriaQuery criteriaQuery, Class<?> domainClas
1019
1040
}
1020
1041
1021
1042
private void updateCriteria (Criteria criteria , ElasticsearchPersistentEntity <?> persistentEntity ) {
1043
+
1022
1044
Field field = criteria .getField ();
1023
1045
1024
1046
if (field == null ) {
1025
1047
return ;
1026
1048
}
1027
1049
1028
- String name = field .getName ();
1029
- ElasticsearchPersistentProperty property = persistentEntity .getPersistentProperty (name );
1050
+ String [] fieldNames = field .getName ().split ("\\ ." );
1051
+ ElasticsearchPersistentEntity <?> currentEntity = persistentEntity ;
1052
+ ElasticsearchPersistentProperty persistentProperty = null ;
1053
+ for (int i = 0 ; i < fieldNames .length ; i ++) {
1054
+ persistentProperty = currentEntity .getPersistentProperty (fieldNames [i ]);
1055
+
1056
+ if (persistentProperty != null ) {
1057
+ fieldNames [i ] = persistentProperty .getFieldName ();
1058
+ try {
1059
+ currentEntity = mappingContext .getPersistentEntity (persistentProperty .getActualType ());
1060
+ } catch (Exception e ) {
1061
+ // using system types like UUIDs will lead to java.lang.reflect.InaccessibleObjectException in JDK 16
1062
+ // so if we cannot get an entity here, bail out.
1063
+ currentEntity = null ;
1064
+ }
1065
+ }
1066
+
1067
+ if (currentEntity == null ) {
1068
+ break ;
1069
+ }
1070
+ }
1071
+
1072
+ field .setName (String .join ("." , fieldNames ));
1030
1073
1031
- if (property != null && property .getName ().equals (name )) {
1032
- field .setName (property .getFieldName ());
1074
+ if (persistentProperty != null ) {
1033
1075
1034
- if (property .hasPropertyConverter ()) {
1076
+ if (persistentProperty .hasPropertyConverter ()) {
1035
1077
ElasticsearchPersistentPropertyConverter propertyConverter = Objects
1036
- .requireNonNull (property .getPropertyConverter ());
1078
+ .requireNonNull (persistentProperty .getPropertyConverter ());
1037
1079
criteria .getQueryCriteriaEntries ().forEach (criteriaEntry -> {
1038
1080
Object value = criteriaEntry .getValue ();
1039
1081
if (value .getClass ().isArray ()) {
@@ -1047,14 +1089,15 @@ private void updateCriteria(Criteria criteria, ElasticsearchPersistentEntity<?>
1047
1089
});
1048
1090
}
1049
1091
1050
- org .springframework .data .elasticsearch .annotations .Field fieldAnnotation = property
1092
+ org .springframework .data .elasticsearch .annotations .Field fieldAnnotation = persistentProperty
1051
1093
.findAnnotation (org .springframework .data .elasticsearch .annotations .Field .class );
1052
1094
1053
1095
if (fieldAnnotation != null ) {
1054
1096
field .setFieldType (fieldAnnotation .type ());
1055
1097
}
1056
1098
}
1057
1099
}
1100
+
1058
1101
// endregion
1059
1102
1060
1103
static class MapValueAccessor {
@@ -1148,7 +1191,6 @@ class ElasticsearchPropertyValueProvider implements PropertyValueProvider<Elasti
1148
1191
this .evaluator = evaluator ;
1149
1192
}
1150
1193
1151
- @ SuppressWarnings ("unchecked" )
1152
1194
@ Override
1153
1195
public <T > T getPropertyValue (ElasticsearchPersistentProperty property ) {
1154
1196
0 commit comments