3030import org .springframework .data .mapping .MappingException ;
3131import org .springframework .data .mapping .PersistentEntity ;
3232import org .springframework .data .mapping .PersistentPropertyAccessor ;
33+ import org .springframework .data .mapping .PersistentPropertyPath ;
34+ import org .springframework .data .mapping .PropertyPath ;
3335import org .springframework .data .mapping .context .MappingContext ;
3436import org .springframework .data .mapping .model .ConvertingPropertyAccessor ;
3537import org .springframework .data .mongodb .core .CollectionOptions .TimeSeriesOptions ;
5052import org .springframework .data .projection .EntityProjection ;
5153import org .springframework .data .projection .EntityProjectionIntrospector ;
5254import org .springframework .data .projection .ProjectionFactory ;
55+ import org .springframework .data .projection .TargetAware ;
5356import org .springframework .data .util .Optionals ;
5457import org .springframework .lang .Nullable ;
5558import org .springframework .util .Assert ;
@@ -117,12 +120,16 @@ <T> Entity<T> forEntity(T entity) {
117120
118121 Assert .notNull (entity , "Bean must not be null" );
119122
123+ if (entity instanceof TargetAware targetAware ) {
124+ return new SimpleMappedEntity ((Map <String , Object >) targetAware .getTarget (), this );
125+ }
126+
120127 if (entity instanceof String ) {
121- return new UnmappedEntity (parse (entity .toString ()));
128+ return new UnmappedEntity (parse (entity .toString ()), this );
122129 }
123130
124131 if (entity instanceof Map ) {
125- return new SimpleMappedEntity ((Map <String , Object >) entity );
132+ return new SimpleMappedEntity ((Map <String , Object >) entity , this );
126133 }
127134
128135 return MappedEntity .of (entity , context , this );
@@ -142,11 +149,11 @@ <T> AdaptibleEntity<T> forEntity(T entity, ConversionService conversionService)
142149 Assert .notNull (conversionService , "ConversionService must not be null" );
143150
144151 if (entity instanceof String ) {
145- return new UnmappedEntity (parse (entity .toString ()));
152+ return new UnmappedEntity (parse (entity .toString ()), this );
146153 }
147154
148155 if (entity instanceof Map ) {
149- return new SimpleMappedEntity ((Map <String , Object >) entity );
156+ return new SimpleMappedEntity ((Map <String , Object >) entity , this );
150157 }
151158
152159 return AdaptibleMappedEntity .of (entity , context , conversionService , this );
@@ -287,7 +294,8 @@ public <T> TypedOperations<T> forType(@Nullable Class<T> entityClass) {
287294 */
288295 public <M , D > EntityProjection <M , D > introspectProjection (Class <M > resultType , Class <D > entityType ) {
289296
290- if (!queryMapper .getMappingContext ().hasPersistentEntityFor (entityType )) {
297+ MongoPersistentEntity <?> persistentEntity = queryMapper .getMappingContext ().getPersistentEntity (entityType );
298+ if (persistentEntity == null && !resultType .isInterface () || ClassUtils .isAssignable (Document .class , resultType )) {
291299 return (EntityProjection ) EntityProjection .nonProjecting (resultType );
292300 }
293301 return introspector .introspect (resultType , entityType );
@@ -369,6 +377,7 @@ private Document getMappedValidator(Validator validator, Class<?> domainType) {
369377 * A representation of information about an entity.
370378 *
371379 * @author Oliver Gierke
380+ * @author Christoph Strobl
372381 * @since 2.1
373382 */
374383 interface Entity <T > {
@@ -471,10 +480,10 @@ default boolean isVersionedEntity() {
471480 /**
472481 * @param sortObject
473482 * @return
474- * @since 3 .1
483+ * @since 4 .1
475484 * @throws IllegalStateException if a sort key yields {@literal null}.
476485 */
477- Map <String , Object > extractKeys (Document sortObject );
486+ Map <String , Object > extractKeys (Document sortObject , Class <?> sourceType );
478487
479488 }
480489
@@ -523,9 +532,11 @@ interface AdaptibleEntity<T> extends Entity<T> {
523532 private static class UnmappedEntity <T extends Map <String , Object >> implements AdaptibleEntity <T > {
524533
525534 private final T map ;
535+ private final EntityOperations entityOperations ;
526536
527- protected UnmappedEntity (T map ) {
537+ protected UnmappedEntity (T map , EntityOperations entityOperations ) {
528538 this .map = map ;
539+ this .entityOperations = entityOperations ;
529540 }
530541
531542 @ Override
@@ -596,13 +607,19 @@ public boolean isNew() {
596607 }
597608
598609 @ Override
599- public Map <String , Object > extractKeys (Document sortObject ) {
610+ public Map <String , Object > extractKeys (Document sortObject , Class <?> sourceType ) {
600611
601612 Map <String , Object > keyset = new LinkedHashMap <>();
602- keyset .put (ID_FIELD , getId ());
613+ MongoPersistentEntity <?> sourceEntity = entityOperations .context .getPersistentEntity (sourceType );
614+ if (sourceEntity != null && sourceEntity .hasIdProperty ()) {
615+ keyset .put (sourceEntity .getRequiredIdProperty ().getName (), getId ());
616+ } else {
617+ keyset .put (ID_FIELD , getId ());
618+ }
603619
604620 for (String key : sortObject .keySet ()) {
605- Object value = BsonUtils .resolveValue (map , key );
621+
622+ Object value = resolveValue (key , sourceEntity );
606623
607624 if (value == null ) {
608625 throw new IllegalStateException (
@@ -614,12 +631,24 @@ public Map<String, Object> extractKeys(Document sortObject) {
614631
615632 return keyset ;
616633 }
634+
635+ @ Nullable
636+ private Object resolveValue (String key , @ Nullable MongoPersistentEntity <?> sourceEntity ) {
637+
638+ if (sourceEntity == null ) {
639+ return BsonUtils .resolveValue (map , key );
640+ }
641+ PropertyPath from = PropertyPath .from (key , sourceEntity .getTypeInformation ());
642+ PersistentPropertyPath <MongoPersistentProperty > persistentPropertyPath = entityOperations .context
643+ .getPersistentPropertyPath (from );
644+ return BsonUtils .resolveValue (map , persistentPropertyPath .toDotPath (p -> p .getFieldName ()));
645+ }
617646 }
618647
619648 private static class SimpleMappedEntity <T extends Map <String , Object >> extends UnmappedEntity <T > {
620649
621- protected SimpleMappedEntity (T map ) {
622- super (map );
650+ protected SimpleMappedEntity (T map , EntityOperations entityOperations ) {
651+ super (map , entityOperations );
623652 }
624653
625654 @ Override
@@ -758,10 +787,15 @@ public boolean isNew() {
758787 }
759788
760789 @ Override
761- public Map <String , Object > extractKeys (Document sortObject ) {
790+ public Map <String , Object > extractKeys (Document sortObject , Class <?> sourceType ) {
762791
763792 Map <String , Object > keyset = new LinkedHashMap <>();
764- keyset .put (entity .getRequiredIdProperty ().getName (), getId ());
793+ MongoPersistentEntity <?> sourceEntity = entityOperations .context .getPersistentEntity (sourceType );
794+ if (sourceEntity != null && sourceEntity .hasIdProperty ()) {
795+ keyset .put (sourceEntity .getRequiredIdProperty ().getName (), getId ());
796+ } else {
797+ keyset .put (entity .getRequiredIdProperty ().getName (), getId ());
798+ }
765799
766800 for (String key : sortObject .keySet ()) {
767801
@@ -933,6 +967,14 @@ interface TypedOperations<T> {
933967 * @since 3.3
934968 */
935969 TimeSeriesOptions mapTimeSeriesOptions (TimeSeriesOptions options );
970+
971+ /**
972+ * @return the name of the id field.
973+ * @since 4.1
974+ */
975+ default String getIdKeyName () {
976+ return ID_FIELD ;
977+ }
936978 }
937979
938980 /**
@@ -1055,6 +1097,11 @@ private String mappedNameOrDefault(String name) {
10551097 MongoPersistentProperty persistentProperty = entity .getPersistentProperty (name );
10561098 return persistentProperty != null ? persistentProperty .getFieldName () : name ;
10571099 }
1100+
1101+ @ Override
1102+ public String getIdKeyName () {
1103+ return entity .getIdProperty ().getName ();
1104+ }
10581105 }
10591106
10601107}
0 commit comments