2020import static org .mockito .Mockito .*;
2121import static org .springframework .data .mongodb .core .DocumentTestUtils .*;
2222
23+ import lombok .Data ;
2324import lombok .EqualsAndHashCode ;
2425import lombok .Getter ;
2526import lombok .RequiredArgsConstructor ;
@@ -2664,8 +2665,8 @@ void projectShouldReadNestedProjection() {
26642665 .and ((target , underlyingType ) -> !converter .conversions .isSimpleType (target )),
26652666 mappingContext );
26662667
2667- EntityProjection <WithNestedProjection , Person > projection = introspector
2668- . introspect ( WithNestedProjection . class , Person .class );
2668+ EntityProjection <WithNestedProjection , Person > projection = introspector . introspect ( WithNestedProjection . class ,
2669+ Person .class );
26692670 WithNestedProjection person = converter .project (projection , source );
26702671
26712672 assertThat (person .getAddresses ()).extracting (AddressProjection ::getStreet ).hasSize (1 ).containsOnly ("hwy" );
@@ -2689,6 +2690,22 @@ void projectShouldReadProjectionWithNestedEntity() {
26892690 assertThat (person .getAddresses ()).extracting (Address ::getStreet ).hasSize (1 ).containsOnly ("hwy" );
26902691 }
26912692
2693+ @ Test // GH-3998
2694+ void shouldReadOpenProjection () {
2695+
2696+ org .bson .Document author = new org .bson .Document ("firstName" , "Walter" ).append ("lastName" , "White" );
2697+ org .bson .Document book = new org .bson .Document ("_id" , "foo" ).append ("name" , "my-book" ).append ("author" , author );
2698+
2699+ EntityProjectionIntrospector introspector = EntityProjectionIntrospector .create (converter .getProjectionFactory (),
2700+ EntityProjectionIntrospector .ProjectionPredicate .typeHierarchy ()
2701+ .and ((target , underlyingType ) -> !converter .conversions .isSimpleType (target )),
2702+ mappingContext );
2703+
2704+ BookProjection projection = converter .project (introspector .introspect (BookProjection .class , Book .class ), book );
2705+
2706+ assertThat (projection .getName ()).isEqualTo ("my-book by Walter White" );
2707+ }
2708+
26922709 static class GenericType <T > {
26932710 T content ;
26942711 }
@@ -3413,11 +3430,56 @@ static class WithFieldWrite {
34133430 @ org .springframework .data .mongodb .core .mapping .Field (
34143431 write = org .springframework .data .mongodb .core .mapping .Field .Write .ALWAYS ) Integer writeAlways ;
34153432
3416- @ org .springframework .data .mongodb .core .mapping .DBRef @ org .springframework .data .mongodb .core .mapping .Field (
3433+ @ org .springframework .data .mongodb .core .mapping .DBRef
3434+ @ org .springframework .data .mongodb .core .mapping .Field (
34173435 write = org .springframework .data .mongodb .core .mapping .Field .Write .NON_NULL ) Person writeNonNullPerson ;
34183436
3419- @ org .springframework .data .mongodb .core .mapping .DBRef @ org .springframework .data .mongodb .core .mapping .Field (
3437+ @ org .springframework .data .mongodb .core .mapping .DBRef
3438+ @ org .springframework .data .mongodb .core .mapping .Field (
34203439 write = org .springframework .data .mongodb .core .mapping .Field .Write .ALWAYS ) Person writeAlwaysPerson ;
34213440
34223441 }
3442+
3443+ interface BookProjection {
3444+
3445+ @ Value ("#{target.name + ' by ' + target.author.firstName + ' ' + target.author.lastName}" )
3446+ String getName ();
3447+ }
3448+
3449+ @ Data
3450+ static class Book {
3451+
3452+ @ Id String id ;
3453+
3454+ String name ;
3455+
3456+ Author author = new Author ();
3457+
3458+ public Book () {}
3459+
3460+ public Book (String id , String name , Author author ) {
3461+ this .id = id ;
3462+ this .name = name ;
3463+ this .author = author ;
3464+ }
3465+ }
3466+
3467+ static class Author {
3468+
3469+ @ Id String id ;
3470+
3471+ String firstName ;
3472+
3473+ String lastName ;
3474+
3475+ public Author () {}
3476+
3477+ public Author (String id , String firstName , String lastName ) {
3478+ this .id = id ;
3479+ this .firstName = firstName ;
3480+ this .lastName = lastName ;
3481+ }
3482+
3483+ }
3484+
34233485}
0 commit comments