#165 generate mapping methods declared in super-classes or implemented interfaces

This commit is contained in:
Andreas Gudian 2014-03-29 21:51:19 +01:00
parent 1eb95e7115
commit a8b153d980
5 changed files with 108 additions and 13 deletions

View File

@ -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<Void, Lis
private List<SourceMethod> retrieveMethods(TypeElement element, boolean mapperRequiresImplementation) {
List<SourceMethod> methods = new ArrayList<SourceMethod>();
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<Void, Lis
}
for ( TypeMirror usedMapper : mapperSettings.uses() ) {
methods.addAll(
retrieveMethods(
(TypeElement) ( (DeclaredType) usedMapper ).asElement(),
false
)
);
methods.addAll( retrieveMethods( asTypeElement( usedMapper ), false ) );
}
}
return methods;
}
private TypeElement asTypeElement(TypeMirror usedMapper) {
return (TypeElement) ( (DeclaredType) usedMapper ).asElement();
}
private List<Element> allEnclosingElementsIncludeSuper(TypeElement element) {
List<Element> enclosedElements = new ArrayList<Element>( 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 <code>true</code>, 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) {

View File

@ -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);
}

View File

@ -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" );

View File

@ -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);
}

View File

@ -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 );