From 8fe7a846c898fbf61165fcfd8578aae9af010e1c Mon Sep 17 00:00:00 2001 From: Andreas Gudian Date: Sun, 16 Feb 2014 22:26:31 +0100 Subject: [PATCH] #103 keep defined accessibility modifier of mapper and mapping methods in the generated code --- .../java/org/mapstruct/ap/model/Mapper.java | 14 +++- .../org/mapstruct/ap/model/MappingMethod.java | 7 ++ .../ap/model/common/Accessibility.java | 56 +++++++++++++++ .../org/mapstruct/ap/model/source/Method.java | 8 +++ ...g.mapstruct.ap.model.BeanMappingMethod.ftl | 2 +- ...pstruct.ap.model.IterableMappingMethod.ftl | 2 +- ...rg.mapstruct.ap.model.MapMappingMethod.ftl | 2 +- .../org.mapstruct.ap.model.Mapper.ftl | 2 +- .../test/accessibility/AccessibilityTest.java | 71 +++++++++++++++++++ .../DefaultSourceTargetMapperAbstr.java | 34 +++++++++ .../DefaultSourceTargetMapperIfc.java | 30 ++++++++ .../ap/test/accessibility/Source.java | 34 +++++++++ .../ap/test/accessibility/Target.java | 34 +++++++++ 13 files changed, 290 insertions(+), 6 deletions(-) create mode 100644 processor/src/main/java/org/mapstruct/ap/model/common/Accessibility.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/accessibility/AccessibilityTest.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/accessibility/DefaultSourceTargetMapperAbstr.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/accessibility/DefaultSourceTargetMapperIfc.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/accessibility/Source.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/accessibility/Target.java diff --git a/processor/src/main/java/org/mapstruct/ap/model/Mapper.java b/processor/src/main/java/org/mapstruct/ap/model/Mapper.java index 842fd3214..80c49de72 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/Mapper.java +++ b/processor/src/main/java/org/mapstruct/ap/model/Mapper.java @@ -23,11 +23,13 @@ import java.util.Collection; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; + import javax.annotation.Generated; import javax.lang.model.element.ElementKind; import javax.lang.model.element.TypeElement; import javax.lang.model.util.Elements; +import org.mapstruct.ap.model.common.Accessibility; import org.mapstruct.ap.model.common.ModelElement; import org.mapstruct.ap.model.common.Type; import org.mapstruct.ap.model.common.TypeFactory; @@ -51,10 +53,12 @@ public class Mapper extends ModelElement { private final List mappingMethods; private final List referencedMappers; private final boolean suppressGeneratorTimestamp; + private final Accessibility accessibility; private Mapper(TypeFactory typeFactory, String packageName, boolean superTypeIsInterface, String interfaceName, String implementationName, List mappingMethods, - List referencedMappers, boolean suppressGeneratorTimestamp) { + List referencedMappers, boolean suppressGeneratorTimestamp, + Accessibility accessibility) { this.packageName = packageName; this.superTypeIsInterface = superTypeIsInterface; this.interfaceName = interfaceName; @@ -64,6 +68,7 @@ public class Mapper extends ModelElement { this.referencedMappers = referencedMappers; this.suppressGeneratorTimestamp = suppressGeneratorTimestamp; this.typeFactory = typeFactory; + this.accessibility = accessibility; } public static class Builder { @@ -114,7 +119,8 @@ public class Mapper extends ModelElement { element.getSimpleName() + IMPLEMENTATION_SUFFIX, mappingMethods, mapperReferences, - suppressGeneratorTimestamp + suppressGeneratorTimestamp, + Accessibility.fromModifiers( element.getModifiers() ) ); } } @@ -222,4 +228,8 @@ public class Mapper extends ModelElement { public List getAnnotations() { return annotations; } + + public Accessibility getAccessibility() { + return accessibility; + } } diff --git a/processor/src/main/java/org/mapstruct/ap/model/MappingMethod.java b/processor/src/main/java/org/mapstruct/ap/model/MappingMethod.java index d313f8f98..eb37ae222 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/MappingMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/model/MappingMethod.java @@ -23,6 +23,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import org.mapstruct.ap.model.common.Accessibility; import org.mapstruct.ap.model.common.ModelElement; import org.mapstruct.ap.model.common.Parameter; import org.mapstruct.ap.model.common.Type; @@ -40,12 +41,14 @@ public abstract class MappingMethod extends ModelElement { private final List parameters; private final Type returnType; private final Parameter targetParameter; + private final Accessibility accessibility; public MappingMethod(Method method) { this.name = method.getName(); this.parameters = method.getParameters(); this.returnType = method.getReturnType(); this.targetParameter = method.getTargetParameter(); + this.accessibility = method.getAccessibility(); } public String getName() { @@ -81,6 +84,10 @@ public abstract class MappingMethod extends ModelElement { return returnType; } + public Accessibility getAccessibility() { + return accessibility; + } + public boolean isExistingInstanceMapping() { return targetParameter != null; } diff --git a/processor/src/main/java/org/mapstruct/ap/model/common/Accessibility.java b/processor/src/main/java/org/mapstruct/ap/model/common/Accessibility.java new file mode 100644 index 000000000..ff8182b4e --- /dev/null +++ b/processor/src/main/java/org/mapstruct/ap/model/common/Accessibility.java @@ -0,0 +1,56 @@ +/** + * 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.model.common; + +import java.util.Set; + +import javax.lang.model.element.Modifier; + +/** + * Accessibility of an element + * + * @author Andreas Gudian + */ +public enum Accessibility { + PRIVATE( "private" ), DEFAULT( "" ), PROTECTED( "protected" ), PUBLIC( "public" ); + + private final String keyword; + + private Accessibility(String keyword) { + this.keyword = keyword; + } + + public String getKeyword() { + return keyword; + } + + public static Accessibility fromModifiers(Set modifiers) { + if ( modifiers.contains( Modifier.PUBLIC ) ) { + return PUBLIC; + } + else if ( modifiers.contains( Modifier.PROTECTED ) ) { + return PROTECTED; + } + else if ( modifiers.contains( Modifier.PRIVATE ) ) { + return PRIVATE; + } + + return DEFAULT; + } +} diff --git a/processor/src/main/java/org/mapstruct/ap/model/source/Method.java b/processor/src/main/java/org/mapstruct/ap/model/source/Method.java index 438503669..873350aea 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/source/Method.java +++ b/processor/src/main/java/org/mapstruct/ap/model/source/Method.java @@ -22,9 +22,11 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; + import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; +import org.mapstruct.ap.model.common.Accessibility; import org.mapstruct.ap.model.common.Parameter; import org.mapstruct.ap.model.common.Type; import org.mapstruct.ap.util.Strings; @@ -46,6 +48,7 @@ public class Method { private final List parameters; private final Parameter targetParameter; private final Type returnType; + private final Accessibility accessibility; private Map> mappings; private IterableMapping iterableMapping; @@ -97,6 +100,7 @@ public class Method { this.mappings = mappings; this.iterableMapping = iterableMapping; this.mapMapping = mapMapping; + this.accessibility = Accessibility.fromModifiers( executable.getModifiers() ); this.targetParameter = determineTargetParameter( parameters ); } @@ -163,6 +167,10 @@ public class Method { return returnType; } + public Accessibility getAccessibility() { + return accessibility; + } + public Map> getMappings() { return mappings; } diff --git a/processor/src/main/resources/org.mapstruct.ap.model.BeanMappingMethod.ftl b/processor/src/main/resources/org.mapstruct.ap.model.BeanMappingMethod.ftl index 690edf872..d28527732 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.BeanMappingMethod.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.BeanMappingMethod.ftl @@ -19,7 +19,7 @@ --> @Override -public <@includeModel object=returnType/> ${name}(<#list parameters as param><@includeModel object=param/><#if param_has_next>, ) { +<#lt>${accessibility.keyword} <@includeModel object=returnType/> ${name}(<#list parameters as param><@includeModel object=param/><#if param_has_next>, ) { if ( <#list sourceParameters as sourceParam>${sourceParam.name} == null<#if sourceParam_has_next> && ) { return<#if returnType.name != "void"> null; } diff --git a/processor/src/main/resources/org.mapstruct.ap.model.IterableMappingMethod.ftl b/processor/src/main/resources/org.mapstruct.ap.model.IterableMappingMethod.ftl index 3182fae1e..c6e7637da 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.IterableMappingMethod.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.IterableMappingMethod.ftl @@ -19,7 +19,7 @@ --> @Override -public <@includeModel object=returnType/> ${name}(<#list parameters as param><@includeModel object=param/><#if param_has_next>, ) { +<#lt>${accessibility.keyword} <@includeModel object=returnType/> ${name}(<#list parameters as param><@includeModel object=param/><#if param_has_next>, ) { if ( ${sourceParameter.name} == null ) { return<#if returnType.name != "void"> null; } diff --git a/processor/src/main/resources/org.mapstruct.ap.model.MapMappingMethod.ftl b/processor/src/main/resources/org.mapstruct.ap.model.MapMappingMethod.ftl index d4eadc94f..7b5cc03c5 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.MapMappingMethod.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.MapMappingMethod.ftl @@ -19,7 +19,7 @@ --> @Override -public <@includeModel object=returnType /> ${name}(<#list parameters as param><@includeModel object=param/><#if param_has_next>, ) { +<#lt>${accessibility.keyword} <@includeModel object=returnType /> ${name}(<#list parameters as param><@includeModel object=param/><#if param_has_next>, ) { if ( ${sourceParameter.name} == null ) { return<#if returnType.name != "void"> null; } diff --git a/processor/src/main/resources/org.mapstruct.ap.model.Mapper.ftl b/processor/src/main/resources/org.mapstruct.ap.model.Mapper.ftl index cbe2ea04e..3c89c56ab 100644 --- a/processor/src/main/resources/org.mapstruct.ap.model.Mapper.ftl +++ b/processor/src/main/resources/org.mapstruct.ap.model.Mapper.ftl @@ -31,7 +31,7 @@ import ${importedType.fullyQualifiedName}; <#list annotations as annotation> <#nt><@includeModel object=annotation/> -public class ${implementationName} <#if superTypeInterface>implements<#else>extends ${interfaceName} { +<#lt>${accessibility.keyword} class ${implementationName} <#if superTypeInterface>implements<#else>extends ${interfaceName} { <#list referencedMappers as mapper> <#nt> <@includeModel object=mapper/> diff --git a/processor/src/test/java/org/mapstruct/ap/test/accessibility/AccessibilityTest.java b/processor/src/test/java/org/mapstruct/ap/test/accessibility/AccessibilityTest.java new file mode 100644 index 000000000..c468bc90c --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/accessibility/AccessibilityTest.java @@ -0,0 +1,71 @@ +/** + * 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.accessibility; + +import static java.lang.reflect.Modifier.isPrivate; +import static java.lang.reflect.Modifier.isProtected; +import static java.lang.reflect.Modifier.isPublic; +import static org.testng.Assert.assertTrue; + +import org.mapstruct.ap.testutil.IssueKey; +import org.mapstruct.ap.testutil.MapperTestBase; +import org.mapstruct.ap.testutil.WithClasses; +import org.testng.annotations.Test; + +/** + * Test for different accessibility modifiers + * + * @author Andreas Gudian + */ +@WithClasses( { Source.class, Target.class, DefaultSourceTargetMapperAbstr.class, DefaultSourceTargetMapperIfc.class } ) +public class AccessibilityTest extends MapperTestBase { + @Test + @IssueKey( "103" ) + public void testGeneratedModifiersFromAbstractClassAreCorrect() throws Exception { + Class defaultFromAbstract = loadForMapper( DefaultSourceTargetMapperAbstr.class ); + + assertTrue( isDefault( defaultFromAbstract.getModifiers() ) ); + + assertTrue( isPublic( modifiersFor( defaultFromAbstract, "publicSourceToTarget" ) ) ); + assertTrue( isProtected( modifiersFor( defaultFromAbstract, "protectedSourceToTarget" ) ) ); + assertTrue( isDefault( modifiersFor( defaultFromAbstract, "defaultSourceToTarget" ) ) ); + } + + @Test + @IssueKey( "103" ) + public void testGeneratedModifiersFromInterfaceAreCorrect() throws Exception { + Class defaultFromIfc = loadForMapper( DefaultSourceTargetMapperIfc.class ); + + assertTrue( isDefault( defaultFromIfc.getModifiers() ) ); + + assertTrue( isPublic( modifiersFor( defaultFromIfc, "implicitlyPublicSoureToTarget" ) ) ); + } + + private static Class loadForMapper(Class mapper) throws ClassNotFoundException { + return Thread.currentThread().getContextClassLoader().loadClass( mapper.getName() + "Impl" ); + } + + private int modifiersFor(Class clazz, String method) throws Exception { + return clazz.getDeclaredMethod( method, Source.class ).getModifiers(); + } + + private static boolean isDefault(int modifiers) { + return !isPublic( modifiers ) && !isProtected( modifiers ) && !isPrivate( modifiers ); + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/accessibility/DefaultSourceTargetMapperAbstr.java b/processor/src/test/java/org/mapstruct/ap/test/accessibility/DefaultSourceTargetMapperAbstr.java new file mode 100644 index 000000000..ff09fb2fb --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/accessibility/DefaultSourceTargetMapperAbstr.java @@ -0,0 +1,34 @@ +/** + * 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.accessibility; + +import org.mapstruct.Mapper; + +/** + * @author Andreas Gudian + * + */ +@Mapper +abstract class DefaultSourceTargetMapperAbstr { + abstract Target defaultSourceToTarget(Source source); + + protected abstract Target protectedSourceToTarget(Source source); + + public abstract Target publicSourceToTarget(Source source); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/accessibility/DefaultSourceTargetMapperIfc.java b/processor/src/test/java/org/mapstruct/ap/test/accessibility/DefaultSourceTargetMapperIfc.java new file mode 100644 index 000000000..ed5c23bb8 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/accessibility/DefaultSourceTargetMapperIfc.java @@ -0,0 +1,30 @@ +/** + * 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.accessibility; + +import org.mapstruct.Mapper; + +/** + * @author Andreas Gudian + * + */ +@Mapper +interface DefaultSourceTargetMapperIfc { + Target implicitlyPublicSoureToTarget(Source source); +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/accessibility/Source.java b/processor/src/test/java/org/mapstruct/ap/test/accessibility/Source.java new file mode 100644 index 000000000..3797b5a16 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/accessibility/Source.java @@ -0,0 +1,34 @@ +/** + * 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.accessibility; + +/** + * @author Andreas Gudian + */ +public class Source { + private String foo; + + public String getFoo() { + return foo; + } + + public void setFoo(String foo) { + this.foo = foo; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/accessibility/Target.java b/processor/src/test/java/org/mapstruct/ap/test/accessibility/Target.java new file mode 100644 index 000000000..da83d0a6a --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/accessibility/Target.java @@ -0,0 +1,34 @@ +/** + * 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.accessibility; + +/** + * @author Andreas Gudian + */ +public class Target { + private String foo; + + public String getFoo() { + return foo; + } + + public void setFoo(String foo) { + this.foo = foo; + } +}