#253, #254 do not collect methods that override Object#equals(Object) or that are overridden by an already collected method from a sub type

This commit is contained in:
Andreas Gudian 2014-07-03 21:52:47 +02:00
parent 644b5ef65a
commit c434e1dcd3
8 changed files with 195 additions and 9 deletions

View File

@ -22,6 +22,7 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.annotation.processing.Messager; import javax.annotation.processing.Messager;
import javax.lang.model.element.Element; import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.ExecutableElement;
@ -30,6 +31,7 @@ import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType; import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types; import javax.lang.model.util.Types;
import javax.tools.Diagnostic.Kind; import javax.tools.Diagnostic.Kind;
@ -62,12 +64,16 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
private Messager messager; private Messager messager;
private TypeFactory typeFactory; private TypeFactory typeFactory;
private Types typeUtils; private Types typeUtils;
private Elements elementUtils;
private TypeMirror javaLangObjectTypeMirror;
@Override @Override
public List<SourceMethod> process(ProcessorContext context, TypeElement mapperTypeElement, Void sourceModel) { public List<SourceMethod> process(ProcessorContext context, TypeElement mapperTypeElement, Void sourceModel) {
this.messager = context.getMessager(); this.messager = context.getMessager();
this.typeFactory = context.getTypeFactory(); this.typeFactory = context.getTypeFactory();
this.typeUtils = context.getTypeUtils(); this.typeUtils = context.getTypeUtils();
this.elementUtils = context.getElementUtils();
this.javaLangObjectTypeMirror = typeFactory.getType( Object.class ).getTypeMirror();
return retrieveMethods( mapperTypeElement, mapperTypeElement ); return retrieveMethods( mapperTypeElement, mapperTypeElement );
} }
@ -88,9 +94,11 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
List<SourceMethod> methods = new ArrayList<SourceMethod>(); List<SourceMethod> methods = new ArrayList<SourceMethod>();
for ( ExecutableElement executable : methodsIn( allEnclosingElementsIncludeSuper( usedMapper ) ) ) { for ( ExecutableElement executable : methodsIn( allEnclosingElementsIncludeSuper( usedMapper ) ) ) {
SourceMethod method = getMethod( usedMapper, executable, mapperToImplement ); if ( isNotObjectEquals( executable ) && wasNotYetOverridden( methods, executable ) ) {
if ( method != null ) { SourceMethod method = getMethod( usedMapper, executable, mapperToImplement );
methods.add( method ); if ( method != null ) {
methods.add( method );
}
} }
} }
@ -111,6 +119,38 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
return methods; return methods;
} }
/**
* @param executable the executable to check
* @return <code>true</code>, iff the executable does not represent {@link java.lang.Object#equals(Object)} or an
* overridden version of it
*/
private boolean isNotObjectEquals(ExecutableElement executable) {
if ( "equals".equals( executable.getSimpleName().toString() )
&& executable.getParameters().size() == 1
&& executable.getParameters().get( 0 ).asType().equals( javaLangObjectTypeMirror ) ) {
return false;
}
return true;
}
/**
* @param methods the list of already collected methods of one type hierarchy (order is from sub-types to
* super-types)
* @param executable the method to check
* @return <code>true</code>, iff the given executable was not yet overridden by a method in the given list.
*/
private boolean wasNotYetOverridden(List<SourceMethod> methods, ExecutableElement executable) {
for ( SourceMethod alreadyAdded : methods ) {
ExecutableElement executableInSubtype = alreadyAdded.getExecutable();
TypeElement declaringType = (TypeElement) executableInSubtype.getEnclosingElement();
if ( elementUtils.overrides( executableInSubtype, executable, declaringType ) ) {
return false;
}
}
return true;
}
private TypeElement asTypeElement(TypeMirror usedMapper) { private TypeElement asTypeElement(TypeMirror usedMapper) {
return (TypeElement) ( (DeclaredType) usedMapper ).asElement(); return (TypeElement) ( (DeclaredType) usedMapper ).asElement();
} }

View File

@ -18,21 +18,24 @@
*/ */
package org.mapstruct.ap.test.abstractclass; package org.mapstruct.ap.test.abstractclass;
import static org.fest.assertions.Assertions.assertThat;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mapstruct.ap.testutil.IssueKey; import org.mapstruct.ap.testutil.IssueKey;
import org.mapstruct.ap.testutil.WithClasses; import org.mapstruct.ap.testutil.WithClasses;
import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner; import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner;
import static org.fest.assertions.Assertions.assertThat;
/** /**
* Test for the generation of implementation of abstract base classes. * Test for the generation of implementation of abstract base classes.
* *
* @author Gunnar Morling * @author Gunnar Morling
*/ */
@WithClasses( { Source.class, Target.class, SourceTargetMapper.class, AbstractBaseMapper.class, @WithClasses( { Source.class, Target.class, SourceTargetMapper.class, AbstractBaseMapper.class,
BaseMapperInterface.class } ) BaseMapperInterface.class,
ReferencedMapper.class,
AbstractReferencedMapper.class,
ReferencedMapperInterface.class } )
@RunWith( AnnotationProcessorTestRunner.class ) @RunWith( AnnotationProcessorTestRunner.class )
public class AbstractClassTest { public class AbstractClassTest {
@ -63,6 +66,8 @@ public class AbstractClassTest {
private void assertResult(Target target) { private void assertResult(Target target) {
assertThat( target ).isNotNull(); assertThat( target ).isNotNull();
assertThat( target.getSize() ).isEqualTo( Long.valueOf( 181 ) ); assertThat( target.getSize() ).isEqualTo( Long.valueOf( 181 ) );
assertThat( target.getBirthday() ).isEqualTo( "26.04.1948" ); assertThat( target.getBirthday() ).isEqualTo( "Birthday: 26.04.1948" );
assertThat( target.getManuallyConverted() ).isEqualTo( 42 );
assertThat( target.isNotAttractingEqualsMethod() ).isTrue();
} }
} }

View File

@ -0,0 +1,50 @@
/**
* 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;
import javax.xml.ws.Holder;
/**
* @author Andreas Gudian
*
*/
public abstract class AbstractReferencedMapper implements ReferencedMapperInterface {
@Override
public int holderToInt(Holder<String> holder) {
return 41;
}
public boolean objectToBoolean(Object obj) {
if ( obj instanceof String ) {
return true;
}
return false;
}
@Override
public boolean equals(Object obj) {
return super.equals( obj );
}
@Override
public int hashCode() {
return super.hashCode();
}
}

View File

@ -0,0 +1,32 @@
/**
* 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;
import javax.xml.ws.Holder;
/**
* @author Andreas Gudian
*
*/
public class ReferencedMapper extends AbstractReferencedMapper {
@Override
public int holderToInt(Holder<String> holder) {
return 42;
}
}

View File

@ -0,0 +1,29 @@
/**
* 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;
import javax.xml.ws.Holder;
/**
* @author Andreas Gudian
*
*/
public interface ReferencedMapperInterface {
int holderToInt(Holder<String> holder);
}

View File

@ -20,10 +20,14 @@ package org.mapstruct.ap.test.abstractclass;
import java.util.Calendar; import java.util.Calendar;
import javax.xml.ws.Holder;
public class Source { public class Source {
private final int size; private final int size;
private final Calendar birthday; private final Calendar birthday;
private final String notAttractingEqualsMethod = "no way";
private final Holder<String> manuallyConverted = new Holder<String>("What is the answer?");
public Source() { public Source() {
size = 181; size = 181;
@ -38,4 +42,12 @@ public class Source {
public Calendar getBirthday() { public Calendar getBirthday() {
return birthday; return birthday;
} }
public String getNotAttractingEqualsMethod() {
return notAttractingEqualsMethod;
}
public Holder<String> getManuallyConverted() {
return manuallyConverted;
}
} }

View File

@ -25,7 +25,7 @@ import java.util.Calendar;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;
@Mapper @Mapper( uses = ReferencedMapper.class )
public abstract class SourceTargetMapper extends AbstractBaseMapper { public abstract class SourceTargetMapper extends AbstractBaseMapper {
public static final SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class ); public static final SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class );
@ -34,6 +34,6 @@ public abstract class SourceTargetMapper extends AbstractBaseMapper {
protected String calendarToString(Calendar calendar) { protected String calendarToString(Calendar calendar) {
DateFormat format = new SimpleDateFormat( "dd.MM.yyyy" ); DateFormat format = new SimpleDateFormat( "dd.MM.yyyy" );
return format.format( calendar.getTime() ); return "Birthday: " + format.format( calendar.getTime() );
} }
} }

View File

@ -22,6 +22,8 @@ public class Target {
private Long size; private Long size;
private String birthday; private String birthday;
private boolean notAttractingEqualsMethod;
private int manuallyConverted;
public Long getSize() { public Long getSize() {
return size; return size;
@ -38,4 +40,20 @@ public class Target {
public void setBirthday(String birthday) { public void setBirthday(String birthday) {
this.birthday = birthday; this.birthday = birthday;
} }
public boolean isNotAttractingEqualsMethod() {
return notAttractingEqualsMethod;
}
public void setNotAttractingEqualsMethod(boolean notAttractingEqualsMethod) {
this.notAttractingEqualsMethod = notAttractingEqualsMethod;
}
public int getManuallyConverted() {
return manuallyConverted;
}
public void setManuallyConverted(int manuallyConverted) {
this.manuallyConverted = manuallyConverted;
}
} }