/** * Copyright 2012-2017 Gunnar Morling (http://www.gunnarmorling.de/) * and/or other contributors as indicated by the @authors tag. See the * copyright.txt file in the distribution for a full listing of all * contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.mapstruct.ap.test.nestedbeans; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; import org.assertj.core.groups.Tuple; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mapstruct.ap.testutil.WithClasses; import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner; import org.mapstruct.ap.testutil.runner.GeneratedSource; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; @WithClasses({ User.class, UserDto.class, Car.class, CarDto.class, House.class, HouseDto.class, Wheel.class, WheelDto.class, Roof.class, RoofDto.class, RoofType.class, ExternalRoofType.class, org.mapstruct.ap.test.nestedbeans.other.CarDto.class, org.mapstruct.ap.test.nestedbeans.other.UserDto.class, org.mapstruct.ap.test.nestedbeans.other.HouseDto.class, org.mapstruct.ap.test.nestedbeans.other.RoofDto.class, org.mapstruct.ap.test.nestedbeans.other.WheelDto.class, UserDtoMapperClassic.class, UserDtoMapperSmart.class, UserDtoUpdateMapperSmart.class }) @RunWith(AnnotationProcessorTestRunner.class) public class NestedSimpleBeansMappingTest { @Rule public final GeneratedSource generatedSource = new GeneratedSource().addComparisonToFixtureFor( UserDtoMapperClassic.class, UserDtoMapperSmart.class, UserDtoUpdateMapperSmart.class ); /** * Extracts all non synthetic declared fields from a class. This is needed, because jacoco adds a synthetic field * to the classes and also assertj does not support testing that all fields are exactly there. * This will be needed until <a href="https://github.com/joel-costigliola/assertj-core/issues/953">953</a> from * assertj-core is implemented. * * @param clazz to extract from * * @return all the non synthetic declared fields */ private static List<Field> extractAllFields(Class<?> clazz) { List<Field> nonSyntheticFields = new ArrayList<Field>(); for ( Field field : clazz.getDeclaredFields() ) { if ( !field.isSynthetic() ) { nonSyntheticFields.add( field ); } } return nonSyntheticFields; } @Test public void shouldHaveAllFields() throws Exception { // If this test fails that means something new was added to the structure of the User/UserDto. // Make sure that the other tests are also updated (the new field is asserted) Object[] userFields = new String[] { "name", "car", "secondCar", "house" }; assertThat( extractAllFields( User.class ) ).extracting( "name" ).containsExactlyInAnyOrder( userFields ); assertThat( extractAllFields( UserDto.class ) ).extracting( "name" ).containsExactlyInAnyOrder( userFields ); Object[] carFields = new String[] { "name", "year", "wheels" }; assertThat( extractAllFields( Car.class ) ).extracting( "name" ).containsExactlyInAnyOrder( carFields ); assertThat( extractAllFields( CarDto.class ) ).extracting( "name" ).containsExactlyInAnyOrder( carFields ); Object[] wheelFields = new String[] { "front", "right" }; assertThat( extractAllFields( Wheel.class ) ).extracting( "name" ).containsExactlyInAnyOrder( wheelFields ); assertThat( extractAllFields( WheelDto.class ) ).extracting( "name" ).containsExactlyInAnyOrder( wheelFields ); Object[] houseFields = new String[] { "name", "year", "roof" }; assertThat( extractAllFields( House.class ) ).extracting( "name" ).containsExactlyInAnyOrder( houseFields ); assertThat( extractAllFields( HouseDto.class ) ).extracting( "name" ).containsExactlyInAnyOrder( houseFields ); Object[] roofFields = new String[] { "color", "type" }; assertThat( extractAllFields( Roof.class ) ).extracting( "name" ).containsExactlyInAnyOrder( roofFields ); assertThat( extractAllFields( RoofDto.class ) ).extracting( "name" ).containsExactlyInAnyOrder( roofFields ); } @Test public void shouldMapNestedBeans() { User user = TestData.createUser(); UserDto classicMapping = UserDtoMapperClassic.INSTANCE.userToUserDto( user ); UserDto smartMapping = UserDtoMapperSmart.INSTANCE.userToUserDto( user ); assertUserDto( classicMapping, user ); assertUserDto( smartMapping, user ); } @Test public void shouldMapUpdateNestedBeans() { User user = TestData.createUser(); user.getCar().setName( null ); // create a pre-exsiting smartMapping UserDto smartMapping = new UserDto(); smartMapping.setCar( new CarDto() ); smartMapping.getCar().setName( "Toyota" ); // action UserDtoUpdateMapperSmart.INSTANCE.userToUserDto( smartMapping, user ); // result assertThat( smartMapping.getName() ).isEqualTo( user.getName() ); assertThat( smartMapping.getCar().getYear() ).isEqualTo( user.getCar().getYear() ); assertThat( smartMapping.getCar().getName() ).isEqualTo( "Toyota" ); assertThat( user.getCar().getName() ).isNull(); assertWheels( smartMapping.getCar().getWheels(), user.getCar().getWheels() ); assertCar( smartMapping.getSecondCar(), user.getSecondCar() ); assertHouse( smartMapping.getHouse(), user.getHouse() ); } private static void assertUserDto(UserDto userDto, User user) { assertThat( userDto ).isNotNull(); assertThat( userDto.getName() ).isEqualTo( user.getName() ); assertCar( userDto.getCar(), user.getCar() ); assertCar( userDto.getSecondCar(), user.getSecondCar() ); assertHouse( userDto.getHouse(), user.getHouse() ); } private static void assertCar(CarDto carDto, Car car) { if ( car == null ) { assertThat( carDto ).isNull(); } else { assertThat( carDto.getName() ).isEqualTo( car.getName() ); assertThat( carDto.getYear() ).isEqualTo( car.getYear() ); assertWheels( carDto.getWheels(), car.getWheels() ); } } private static void assertWheels(List<WheelDto> wheelDtos, List<Wheel> wheels) { List<Tuple> wheelTuples = wheels.stream().map( new Function<Wheel, Tuple>() { @Override public Tuple apply(Wheel wheel) { return tuple( wheel.isFront(), wheel.isRight() ); } } ).collect( Collectors.<Tuple>toList() ); assertThat( wheelDtos ) .extracting( "front", "right" ) .containsExactlyElementsOf( wheelTuples ); } private static void assertHouse(HouseDto houseDto, House house) { assertThat( houseDto.getName() ).isEqualTo( house.getName() ); assertThat( houseDto.getYear() ).isEqualTo( house.getYear() ); assertRoof( houseDto.getRoof(), house.getRoof() ); } private static void assertRoof(RoofDto roofDto, Roof roof) { assertThat( roofDto.getColor() ).isEqualTo( String.valueOf( roof.getColor() ) ); assertThat( roofDto.getType().name() ).isEqualTo( roof.getType().name() ); } }