From 873e0919757a1649ab575d8a243c18342a44ad1a Mon Sep 17 00:00:00 2001 From: Gunnar Morling Date: Sat, 16 Jun 2012 10:51:05 +0200 Subject: [PATCH] Matching mappable properties by name and type; excluding non-matching properties in native mapper --- .../maple/ap/MapperGenerationVisitor.java | 48 +++++++---- .../de/moapa/maple/ap/model/Property.java | 85 +++++++++++++++++++ .../java/de/moapa/maple/ap/model/Type.java | 51 +++++++++++ .../native-mapper-implementation.ftl | 2 +- .../de/moapa/maple/ap/test/CarMapperTest.java | 51 +++++++++-- .../maple/ap/test/NativeCarMapperTest.java | 44 ++++++++-- .../de/moapa/maple/ap/test/model/Car.java | 14 ++- .../de/moapa/maple/ap/test/model/CarDto.java | 14 ++- .../de/moapa/maple/ap/test/model/Person.java | 36 ++++++++ .../moapa/maple/ap/test/model/PersonDto.java | 36 ++++++++ 10 files changed, 347 insertions(+), 34 deletions(-) create mode 100644 processor/src/main/java/de/moapa/maple/ap/model/Property.java create mode 100644 processor/src/test/java/de/moapa/maple/ap/test/model/Person.java create mode 100644 processor/src/test/java/de/moapa/maple/ap/test/model/PersonDto.java diff --git a/processor/src/main/java/de/moapa/maple/ap/MapperGenerationVisitor.java b/processor/src/main/java/de/moapa/maple/ap/MapperGenerationVisitor.java index a139ebee4..10241428b 100644 --- a/processor/src/main/java/de/moapa/maple/ap/MapperGenerationVisitor.java +++ b/processor/src/main/java/de/moapa/maple/ap/MapperGenerationVisitor.java @@ -45,6 +45,7 @@ import de.moapa.maple.ap.model.Binding; import de.moapa.maple.ap.model.Mapper; import de.moapa.maple.ap.model.MapperMethod; import de.moapa.maple.ap.model.Parameter; +import de.moapa.maple.ap.model.Property; import de.moapa.maple.ap.model.Type; import de.moapa.maple.ap.writer.DozerModelWriter; import de.moapa.maple.ap.writer.ModelWriter; @@ -169,37 +170,50 @@ public class MapperGenerationVisitor extends ElementKindVisitor6 { Element returnTypeElement = typeUtils.asElement( method.getReturnType() ); - Set writableTargetProperties = new LinkedHashSet(); + Set writableTargetProperties = new LinkedHashSet(); //collect writable properties of the target type for ( ExecutableElement oneMethod : methodsIn( returnTypeElement.getEnclosedElements() ) ) { if ( oneMethod.getSimpleName().toString().startsWith( "set" ) && oneMethod.getParameters().size() == 1 ) { - writableTargetProperties.add( oneMethod.getSimpleName().toString().substring( 3 ) ); + writableTargetProperties.add( + new Property( + retrieveParameter( oneMethod ).getType(), + oneMethod.getSimpleName().toString().substring( 3 ) + ) + ); } } //collect readable properties of the source type Element parameterElement = typeUtils.asElement( method.getParameters().get( 0 ).asType() ); - Set readableSourceProperties = new LinkedHashSet(); + Set readableSourceProperties = new LinkedHashSet(); for ( ExecutableElement oneMethod : methodsIn( parameterElement.getEnclosedElements() ) ) { + //TODO: consider is/has if ( oneMethod.getSimpleName().toString().startsWith( "get" ) && oneMethod.getParameters().isEmpty() && oneMethod.getReturnType().getKind() != TypeKind.VOID ) { - readableSourceProperties.add( oneMethod.getSimpleName().toString().substring( 3 ) ); + readableSourceProperties.add( + new Property( + retrieveReturnType( oneMethod ), + oneMethod.getSimpleName().toString().substring( 3 ) + ) + ); } } writableTargetProperties.retainAll( readableSourceProperties ); - for ( String oneWritableProperty : writableTargetProperties ) { - bindings.put( oneWritableProperty, new Binding( oneWritableProperty, oneWritableProperty ) ); + for ( Property oneWritableProperty : writableTargetProperties ) { + bindings.put( + oneWritableProperty.getName(), + new Binding( oneWritableProperty.getName(), oneWritableProperty.getName() ) + ); } - } private void retrieveBindings(AnnotationMirror annotationMirror, Map bindings) { @@ -278,21 +292,23 @@ public class MapperGenerationVisitor extends ElementKindVisitor6 { return new Parameter( parameter.getSimpleName().toString(), - new Type( - elementUtils.getPackageOf( parameter ).getQualifiedName().toString(), - typeUtils.asElement( parameter.asType() ).getSimpleName().toString() - ) + retrieveType( parameter.asType() ) ); } private Type retrieveReturnType(ExecutableElement method) { - Element returnTypeElement = typeUtils.asElement( method.getReturnType() ); + return retrieveType( method.getReturnType() ); + } - return new Type( - elementUtils.getPackageOf( returnTypeElement ).getQualifiedName().toString(), - returnTypeElement.getSimpleName().toString() - ); + private Type retrieveType(TypeMirror mirror) { + + if ( mirror.getKind() == TypeKind.DECLARED ) { + return getType( ( (DeclaredType) mirror ).asElement() ); + } + else { + return new Type( null, mirror.toString() ); + } } private AnnotationMirror getAnnotation(TypeElement element, String annotationName) { diff --git a/processor/src/main/java/de/moapa/maple/ap/model/Property.java b/processor/src/main/java/de/moapa/maple/ap/model/Property.java new file mode 100644 index 000000000..ea630db2c --- /dev/null +++ b/processor/src/main/java/de/moapa/maple/ap/model/Property.java @@ -0,0 +1,85 @@ +/** + * Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) + * + * 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 de.moapa.maple.ap.model; + +/** + * Represents a property of a Java bean. + * + * @author Gunnar Morling + */ +public class Property { + + private final Type type; + private final String name; + + public Property(Type type, String name) { + this.type = type; + this.name = name; + } + + public Type getType() { + return type; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return "Property [type=" + type + ", name=" + name + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ( ( name == null ) ? 0 : name.hashCode() ); + result = prime * result + ( ( type == null ) ? 0 : type.hashCode() ); + return result; + } + + @Override + public boolean equals(Object obj) { + if ( this == obj ) { + return true; + } + if ( obj == null ) { + return false; + } + if ( getClass() != obj.getClass() ) { + return false; + } + Property other = (Property) obj; + if ( name == null ) { + if ( other.name != null ) { + return false; + } + } + else if ( !name.equals( other.name ) ) { + return false; + } + if ( type == null ) { + if ( other.type != null ) { + return false; + } + } + else if ( !type.equals( other.type ) ) { + return false; + } + return true; + } +} diff --git a/processor/src/main/java/de/moapa/maple/ap/model/Type.java b/processor/src/main/java/de/moapa/maple/ap/model/Type.java index 7613aad2c..743d3e17b 100644 --- a/processor/src/main/java/de/moapa/maple/ap/model/Type.java +++ b/processor/src/main/java/de/moapa/maple/ap/model/Type.java @@ -15,6 +15,11 @@ */ package de.moapa.maple.ap.model; +/** + * Represents the type of a bean property, parameter etc. + * + * @author Gunnar Morling + */ public class Type { private final String packageName; @@ -33,4 +38,50 @@ public class Type { public String getName() { return name; } + + @Override + public String toString() { + return "Type [packageName=" + packageName + ", name=" + name + "]"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ( ( name == null ) ? 0 : name.hashCode() ); + result = prime * result + + ( ( packageName == null ) ? 0 : packageName.hashCode() ); + return result; + } + + @Override + public boolean equals(Object obj) { + if ( this == obj ) { + return true; + } + if ( obj == null ) { + return false; + } + if ( getClass() != obj.getClass() ) { + return false; + } + Type other = (Type) obj; + if ( name == null ) { + if ( other.name != null ) { + return false; + } + } + else if ( !name.equals( other.name ) ) { + return false; + } + if ( packageName == null ) { + if ( other.packageName != null ) { + return false; + } + } + else if ( !packageName.equals( other.packageName ) ) { + return false; + } + return true; + } } diff --git a/processor/src/main/resources/native-mapper-implementation.ftl b/processor/src/main/resources/native-mapper-implementation.ftl index 26ff28c97..cd0cae8aa 100644 --- a/processor/src/main/resources/native-mapper-implementation.ftl +++ b/processor/src/main/resources/native-mapper-implementation.ftl @@ -18,8 +18,8 @@ package ${packageName}; public class ${implementationType} implements ${interfaceType} { - <#list mapperMethods as oneMethod> + public ${oneMethod.returnType.name} ${oneMethod.name}(${oneMethod.parameter.type.name} ${oneMethod.parameter.name}) { ${oneMethod.returnType.name} convertedObject = new ${oneMethod.returnType.name}(); diff --git a/processor/src/test/java/de/moapa/maple/ap/test/CarMapperTest.java b/processor/src/test/java/de/moapa/maple/ap/test/CarMapperTest.java index 6e6e5b69d..77a21d206 100644 --- a/processor/src/test/java/de/moapa/maple/ap/test/CarMapperTest.java +++ b/processor/src/test/java/de/moapa/maple/ap/test/CarMapperTest.java @@ -23,6 +23,8 @@ import de.moapa.maple.ap.test.model.Car; import de.moapa.maple.ap.test.model.CarDto; import de.moapa.maple.ap.test.model.CarMapper; import de.moapa.maple.ap.test.model.IntToStringConverter; +import de.moapa.maple.ap.test.model.Person; +import de.moapa.maple.ap.test.model.PersonDto; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -40,7 +42,14 @@ public class CarMapperTest extends MapperTestBase { public void generateMapperImplementation() { diagnostics = new DiagnosticCollector(); - File[] sourceFiles = getSourceFiles( Car.class, CarDto.class, CarMapper.class, IntToStringConverter.class ); + File[] sourceFiles = getSourceFiles( + Car.class, + CarDto.class, + Person.class, + PersonDto.class, + CarMapper.class, + IntToStringConverter.class + ); boolean compilationSuccessful = compile( diagnostics, sourceFiles ); @@ -58,7 +67,7 @@ public class CarMapperTest extends MapperTestBase { public void shouldMapAttributeByName() { //given - Car car = new Car( "Morris", 2, 1980 ); + Car car = new Car( "Morris", 2, 1980, new Person( "Bob" ) ); //when CarDto carDto = CarMapper.INSTANCE.carToCarDto( car ); @@ -68,11 +77,41 @@ public class CarMapperTest extends MapperTestBase { assertThat( carDto.getMake() ).isEqualTo( car.getMake() ); } + @Test + public void shouldMapReferenceAttribute() { + + //given + Car car = new Car( "Morris", 2, 1980, new Person( "Bob" ) ); + + //when + CarDto carDto = CarMapper.INSTANCE.carToCarDto( car ); + + //then + assertThat( carDto ).isNotNull(); + assertThat( carDto.getDriver() ).isNotNull(); + assertThat( carDto.getDriver().getName() ).isEqualTo( "Bob" ); + } + + @Test + public void shouldReverseMapReferenceAttribute() { + + //given + CarDto carDto = new CarDto( "Morris", 2, "1980", new PersonDto( "Bob" ) ); + + //when + Car car = CarMapper.INSTANCE.carDtoToCar( carDto ); + + //then + assertThat( car ).isNotNull(); + assertThat( car.getDriver() ).isNotNull(); + assertThat( car.getDriver().getName() ).isEqualTo( "Bob" ); + } + @Test public void shouldMapAttributeWithCustomMapping() { //given - Car car = new Car( "Morris", 2, 1980 ); + Car car = new Car( "Morris", 2, 1980, new Person( "Bob" ) ); //when CarDto carDto = CarMapper.INSTANCE.carToCarDto( car ); @@ -86,7 +125,7 @@ public class CarMapperTest extends MapperTestBase { public void shouldConsiderCustomMappingForReverseMapping() { //given - CarDto carDto = new CarDto( "Morris", 2, "1980" ); + CarDto carDto = new CarDto( "Morris", 2, "1980", new PersonDto( "Bob" ) ); //when Car car = CarMapper.INSTANCE.carDtoToCar( carDto ); @@ -100,7 +139,7 @@ public class CarMapperTest extends MapperTestBase { public void shouldApplyConverter() { //given - Car car = new Car( "Morris", 2, 1980 ); + Car car = new Car( "Morris", 2, 1980, new Person( "Bob" ) ); //when CarDto carDto = CarMapper.INSTANCE.carToCarDto( car ); @@ -114,7 +153,7 @@ public class CarMapperTest extends MapperTestBase { public void shouldApplyConverterForReverseMapping() { //given - CarDto carDto = new CarDto( "Morris", 2, "1980" ); + CarDto carDto = new CarDto( "Morris", 2, "1980", new PersonDto( "Bob" ) ); //when Car car = CarMapper.INSTANCE.carDtoToCar( carDto ); diff --git a/processor/src/test/java/de/moapa/maple/ap/test/NativeCarMapperTest.java b/processor/src/test/java/de/moapa/maple/ap/test/NativeCarMapperTest.java index 9edca46a4..2d531309e 100644 --- a/processor/src/test/java/de/moapa/maple/ap/test/NativeCarMapperTest.java +++ b/processor/src/test/java/de/moapa/maple/ap/test/NativeCarMapperTest.java @@ -23,6 +23,8 @@ import de.moapa.maple.ap.test.model.Car; import de.moapa.maple.ap.test.model.CarDto; import de.moapa.maple.ap.test.model.IntToStringConverter; import de.moapa.maple.ap.test.model.NativeCarMapper; +import de.moapa.maple.ap.test.model.Person; +import de.moapa.maple.ap.test.model.PersonDto; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -43,6 +45,8 @@ public class NativeCarMapperTest extends MapperTestBase { File[] sourceFiles = getSourceFiles( Car.class, CarDto.class, + Person.class, + PersonDto.class, NativeCarMapper.class, IntToStringConverter.class ); @@ -63,7 +67,7 @@ public class NativeCarMapperTest extends MapperTestBase { public void shouldMapAttributeByName() { //given - Car car = new Car( "Morris", 2, 1980 ); + Car car = new Car( "Morris", 2, 1980, new Person( "Bob" ) ); //when CarDto carDto = NativeCarMapper.INSTANCE.carToCarDto( car ); @@ -73,11 +77,41 @@ public class NativeCarMapperTest extends MapperTestBase { assertThat( carDto.getMake() ).isEqualTo( car.getMake() ); } + @Test(enabled = false) + public void shouldMapReferenceAttribute() { + + //given + Car car = new Car( "Morris", 2, 1980, new Person( "Bob" ) ); + + //when + CarDto carDto = NativeCarMapper.INSTANCE.carToCarDto( car ); + + //then + assertThat( carDto ).isNotNull(); + assertThat( carDto.getDriver() ).isNotNull(); + assertThat( carDto.getDriver().getName() ).isEqualTo( "Bob" ); + } + + @Test(enabled = false) + public void shouldReverseMapReferenceAttribute() { + + //given + CarDto carDto = new CarDto( "Morris", 2, "1980", new PersonDto( "Bob" ) ); + + //when + Car car = NativeCarMapper.INSTANCE.carDtoToCar( carDto ); + + //then + assertThat( car ).isNotNull(); + assertThat( car.getDriver() ).isNotNull(); + assertThat( car.getDriver().getName() ).isEqualTo( "Bob" ); + } + @Test public void shouldMapAttributeWithCustomMapping() { //given - Car car = new Car( "Morris", 2, 1980 ); + Car car = new Car( "Morris", 2, 1980, new Person( "Bob" ) ); //when CarDto carDto = NativeCarMapper.INSTANCE.carToCarDto( car ); @@ -91,7 +125,7 @@ public class NativeCarMapperTest extends MapperTestBase { public void shouldConsiderCustomMappingForReverseMapping() { //given - CarDto carDto = new CarDto( "Morris", 2, "1980" ); + CarDto carDto = new CarDto( "Morris", 2, "1980", new PersonDto( "Bob" ) ); //when Car car = NativeCarMapper.INSTANCE.carDtoToCar( carDto ); @@ -105,7 +139,7 @@ public class NativeCarMapperTest extends MapperTestBase { public void shouldApplyConverter() { //given - Car car = new Car( "Morris", 2, 1980 ); + Car car = new Car( "Morris", 2, 1980, new Person( "Bob" ) ); //when CarDto carDto = NativeCarMapper.INSTANCE.carToCarDto( car ); @@ -119,7 +153,7 @@ public class NativeCarMapperTest extends MapperTestBase { public void shouldApplyConverterForReverseMapping() { //given - CarDto carDto = new CarDto( "Morris", 2, "1980" ); + CarDto carDto = new CarDto( "Morris", 2, "1980", new PersonDto( "Bob" ) ); //when Car car = NativeCarMapper.INSTANCE.carDtoToCar( carDto ); diff --git a/processor/src/test/java/de/moapa/maple/ap/test/model/Car.java b/processor/src/test/java/de/moapa/maple/ap/test/model/Car.java index 9a6d0bb29..b2d76d93a 100644 --- a/processor/src/test/java/de/moapa/maple/ap/test/model/Car.java +++ b/processor/src/test/java/de/moapa/maple/ap/test/model/Car.java @@ -18,18 +18,18 @@ package de.moapa.maple.ap.test.model; public class Car { private String make; - private int numberOfSeats; - private int yearOfManufacture; + private Person driver; public Car() { } - public Car(String make, int numberOfSeats, int yearOfManufacture) { + public Car(String make, int numberOfSeats, int yearOfManufacture, Person driver) { this.make = make; this.numberOfSeats = numberOfSeats; this.yearOfManufacture = yearOfManufacture; + this.driver = driver; } public String getMake() { @@ -55,4 +55,12 @@ public class Car { public void setYearOfManufacture(int yearOfManufacture) { this.yearOfManufacture = yearOfManufacture; } + + public Person getDriver() { + return driver; + } + + public void setDriver(Person driver) { + this.driver = driver; + } } diff --git a/processor/src/test/java/de/moapa/maple/ap/test/model/CarDto.java b/processor/src/test/java/de/moapa/maple/ap/test/model/CarDto.java index da332de16..62ff0cfa0 100644 --- a/processor/src/test/java/de/moapa/maple/ap/test/model/CarDto.java +++ b/processor/src/test/java/de/moapa/maple/ap/test/model/CarDto.java @@ -18,18 +18,18 @@ package de.moapa.maple.ap.test.model; public class CarDto { private String make; - private int seatCount; - private String manufacturingYear; + private PersonDto driver; public CarDto() { } - public CarDto(String make, int seatCount, String manufacturingYear) { + public CarDto(String make, int seatCount, String manufacturingYear, PersonDto driver) { this.make = make; this.seatCount = seatCount; this.manufacturingYear = manufacturingYear; + this.driver = driver; } public String getMake() { @@ -55,4 +55,12 @@ public class CarDto { public void setManufacturingYear(String manufacturingYear) { this.manufacturingYear = manufacturingYear; } + + public PersonDto getDriver() { + return driver; + } + + public void setDriver(PersonDto driver) { + this.driver = driver; + } } diff --git a/processor/src/test/java/de/moapa/maple/ap/test/model/Person.java b/processor/src/test/java/de/moapa/maple/ap/test/model/Person.java new file mode 100644 index 000000000..02715a86b --- /dev/null +++ b/processor/src/test/java/de/moapa/maple/ap/test/model/Person.java @@ -0,0 +1,36 @@ +/** + * Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) + * + * 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 de.moapa.maple.ap.test.model; + +public class Person { + + private String name; + + public Person() { + } + + public Person(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/processor/src/test/java/de/moapa/maple/ap/test/model/PersonDto.java b/processor/src/test/java/de/moapa/maple/ap/test/model/PersonDto.java new file mode 100644 index 000000000..35f765f0f --- /dev/null +++ b/processor/src/test/java/de/moapa/maple/ap/test/model/PersonDto.java @@ -0,0 +1,36 @@ +/** + * Copyright 2012 Gunnar Morling (http://www.gunnarmorling.de/) + * + * 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 de.moapa.maple.ap.test.model; + +public class PersonDto { + + private String name; + + public PersonDto() { + } + + public PersonDto(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +}