From a8b153d9808f3d0615983e24f350c4c65f5408a3 Mon Sep 17 00:00:00 2001 From: Andreas Gudian Date: Sat, 29 Mar 2014 21:51:19 +0100 Subject: [PATCH] #165 generate mapping methods declared in super-classes or implemented interfaces --- .../processor/MethodRetrievalProcessor.java | 36 +++++++++++++++---- .../abstractclass/AbstractBaseMapper.java | 27 ++++++++++++++ .../test/abstractclass/AbstractClassTest.java | 29 ++++++++++++--- .../abstractclass/BaseMapperInterface.java | 27 ++++++++++++++ .../abstractclass/SourceTargetMapper.java | 2 +- 5 files changed, 108 insertions(+), 13 deletions(-) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/abstractclass/AbstractBaseMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/abstractclass/BaseMapperInterface.java diff --git a/processor/src/main/java/org/mapstruct/ap/processor/MethodRetrievalProcessor.java b/processor/src/main/java/org/mapstruct/ap/processor/MethodRetrievalProcessor.java index 3a5730637..1f074e7a3 100644 --- a/processor/src/main/java/org/mapstruct/ap/processor/MethodRetrievalProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/processor/MethodRetrievalProcessor.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Map; import javax.annotation.processing.Messager; +import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; @@ -89,7 +90,7 @@ public class MethodRetrievalProcessor implements ModelElementProcessor retrieveMethods(TypeElement element, boolean mapperRequiresImplementation) { List methods = new ArrayList(); - for ( ExecutableElement executable : methodsIn( element.getEnclosedElements() ) ) { + for ( ExecutableElement executable : methodsIn( allEnclosingElementsIncludeSuper( element ) ) ) { SourceMethod method = getMethod( element, executable, mapperRequiresImplementation ); if ( method != null ) { methods.add( method ); @@ -106,18 +107,39 @@ public class MethodRetrievalProcessor implements ModelElementProcessor allEnclosingElementsIncludeSuper(TypeElement element) { + List enclosedElements = new ArrayList( element.getEnclosedElements() ); + for ( TypeMirror interfaceType : element.getInterfaces() ) { + enclosedElements.addAll( allEnclosingElementsIncludeSuper( asTypeElement( interfaceType ) ) ); + } + + if ( hasNonObjectSuperclass( element ) ) { + enclosedElements.addAll( allEnclosingElementsIncludeSuper( asTypeElement( element.getSuperclass() ) ) ); + } + + return enclosedElements; + } + + /** + * @param element the type element to check + * @return true, iff the type has a super-class that is not java.lang.Object + */ + private boolean hasNonObjectSuperclass(TypeElement element) { + return element.getSuperclass().getKind() == TypeKind.DECLARED + && asTypeElement( element.getSuperclass() ).getSuperclass().getKind() == TypeKind.DECLARED; + } + private SourceMethod getMethod(TypeElement element, ExecutableElement method, boolean mapperRequiresImplementation) { diff --git a/processor/src/test/java/org/mapstruct/ap/test/abstractclass/AbstractBaseMapper.java b/processor/src/test/java/org/mapstruct/ap/test/abstractclass/AbstractBaseMapper.java new file mode 100644 index 000000000..71540b642 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/abstractclass/AbstractBaseMapper.java @@ -0,0 +1,27 @@ +/** + * Copyright 2012-2014 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.abstractclass; + +/** + * @author Andreas Gudian + * + */ +public abstract class AbstractBaseMapper implements BaseMapperInterface { + public abstract Target sourceToTargetFromBaseMapper(Source source); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/abstractclass/AbstractClassTest.java b/processor/src/test/java/org/mapstruct/ap/test/abstractclass/AbstractClassTest.java index f258c3718..10ad87d1d 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/abstractclass/AbstractClassTest.java +++ b/processor/src/test/java/org/mapstruct/ap/test/abstractclass/AbstractClassTest.java @@ -18,28 +18,47 @@ */ package org.mapstruct.ap.test.abstractclass; +import static org.fest.assertions.Assertions.assertThat; + import org.mapstruct.ap.testutil.IssueKey; import org.mapstruct.ap.testutil.MapperTestBase; import org.mapstruct.ap.testutil.WithClasses; import org.testng.annotations.Test; -import static org.fest.assertions.Assertions.assertThat; - /** * Test for the generation of implementation of abstract base classes. * * @author Gunnar Morling */ -@WithClasses({ Source.class, Target.class, SourceTargetMapper.class }) +@WithClasses( { Source.class, Target.class, SourceTargetMapper.class, AbstractBaseMapper.class, + BaseMapperInterface.class } ) public class AbstractClassTest extends MapperTestBase { @Test - @IssueKey("64") + @IssueKey( "64" ) public void shouldCreateImplementationOfAbstractMethod() { Source source = new Source(); - Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source ); + assertResult( SourceTargetMapper.INSTANCE.sourceToTarget( source ) ); + } + @Test + @IssueKey( "165" ) + public void shouldCreateImplementationOfMethodFromSuper() { + Source source = new Source(); + + assertResult( SourceTargetMapper.INSTANCE.sourceToTargetFromBaseMapper( source ) ); + } + + @Test + @IssueKey( "165" ) + public void shouldCreateImplementationOfMethodFromInterface() { + Source source = new Source(); + + assertResult( SourceTargetMapper.INSTANCE.sourceToTargetFromBaseMapperInterface( source ) ); + } + + private void assertResult(Target target) { assertThat( target ).isNotNull(); assertThat( target.getSize() ).isEqualTo( Long.valueOf( 181 ) ); assertThat( target.getBirthday() ).isEqualTo( "26.04.1948" ); diff --git a/processor/src/test/java/org/mapstruct/ap/test/abstractclass/BaseMapperInterface.java b/processor/src/test/java/org/mapstruct/ap/test/abstractclass/BaseMapperInterface.java new file mode 100644 index 000000000..c8d8b9982 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/abstractclass/BaseMapperInterface.java @@ -0,0 +1,27 @@ +/** + * Copyright 2012-2014 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.abstractclass; + +/** + * @author Andreas Gudian + * + */ +public interface BaseMapperInterface { + Target sourceToTargetFromBaseMapperInterface(Source source); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/abstractclass/SourceTargetMapper.java b/processor/src/test/java/org/mapstruct/ap/test/abstractclass/SourceTargetMapper.java index a4b7fd429..846154fa6 100644 --- a/processor/src/test/java/org/mapstruct/ap/test/abstractclass/SourceTargetMapper.java +++ b/processor/src/test/java/org/mapstruct/ap/test/abstractclass/SourceTargetMapper.java @@ -26,7 +26,7 @@ import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @Mapper -public abstract class SourceTargetMapper { +public abstract class SourceTargetMapper extends AbstractBaseMapper { public static final SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class );