From 60caf959e3cb0969943347a51ad9d1c37ce7c045 Mon Sep 17 00:00:00 2001 From: Ivo Smid Date: Tue, 11 Aug 2015 21:58:46 +0200 Subject: [PATCH] 603 - Java 8 - Cant use static method on interface with decorators. --- .../mapstruct/ap/test/bugs/_603/Source.java | 22 +++++++++ .../ap/test/bugs/_603/SourceTargetMapper.java | 45 ++++++++++++++++++ .../_603/SourceTargetMapperDecorator.java | 33 +++++++++++++ .../mapstruct/ap/test/bugs/_603/Target.java | 40 ++++++++++++++++ .../ap/test/bugs/_603/Issue603Test.java | 39 ++++++++++++++++ parent/pom.xml | 6 +-- .../ap/internal/util/Executables.java | 46 ++++++++++++++++++- 7 files changed, 226 insertions(+), 5 deletions(-) create mode 100644 integrationtest/src/test/resources/java8Test/src/main/java/org/mapstruct/ap/test/bugs/_603/Source.java create mode 100644 integrationtest/src/test/resources/java8Test/src/main/java/org/mapstruct/ap/test/bugs/_603/SourceTargetMapper.java create mode 100644 integrationtest/src/test/resources/java8Test/src/main/java/org/mapstruct/ap/test/bugs/_603/SourceTargetMapperDecorator.java create mode 100644 integrationtest/src/test/resources/java8Test/src/main/java/org/mapstruct/ap/test/bugs/_603/Target.java create mode 100644 integrationtest/src/test/resources/java8Test/src/test/java/org/mapstruct/ap/test/bugs/_603/Issue603Test.java diff --git a/integrationtest/src/test/resources/java8Test/src/main/java/org/mapstruct/ap/test/bugs/_603/Source.java b/integrationtest/src/test/resources/java8Test/src/main/java/org/mapstruct/ap/test/bugs/_603/Source.java new file mode 100644 index 000000000..e3cc530c0 --- /dev/null +++ b/integrationtest/src/test/resources/java8Test/src/main/java/org/mapstruct/ap/test/bugs/_603/Source.java @@ -0,0 +1,22 @@ +/** + * Copyright 2012-2015 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.bugs._603; + +public class Source { +} diff --git a/integrationtest/src/test/resources/java8Test/src/main/java/org/mapstruct/ap/test/bugs/_603/SourceTargetMapper.java b/integrationtest/src/test/resources/java8Test/src/main/java/org/mapstruct/ap/test/bugs/_603/SourceTargetMapper.java new file mode 100644 index 000000000..9ab53c62a --- /dev/null +++ b/integrationtest/src/test/resources/java8Test/src/main/java/org/mapstruct/ap/test/bugs/_603/SourceTargetMapper.java @@ -0,0 +1,45 @@ +/** + * Copyright 2012-2015 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.bugs._603; + +import org.mapstruct.DecoratedWith; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.Mappings; +import org.mapstruct.factory.Mappers; + +@Mapper +@DecoratedWith(SourceTargetMapperDecorator.class) +public interface SourceTargetMapper { + SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class ); + + @Mappings({ + @Mapping(target = "value1", expression = "java( SourceTargetMapper.mapA() )"), + @Mapping(target = "value2", expression = "java( this.mapB() )") + }) + Target mapSourceToTarget(Source source); + + static String mapA() { + return "foo"; + } + + default String mapB() { + return "bar"; + } +} diff --git a/integrationtest/src/test/resources/java8Test/src/main/java/org/mapstruct/ap/test/bugs/_603/SourceTargetMapperDecorator.java b/integrationtest/src/test/resources/java8Test/src/main/java/org/mapstruct/ap/test/bugs/_603/SourceTargetMapperDecorator.java new file mode 100644 index 000000000..d062062c0 --- /dev/null +++ b/integrationtest/src/test/resources/java8Test/src/main/java/org/mapstruct/ap/test/bugs/_603/SourceTargetMapperDecorator.java @@ -0,0 +1,33 @@ +/** + * Copyright 2012-2015 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.bugs._603; + +public abstract class SourceTargetMapperDecorator implements SourceTargetMapper { + + private final SourceTargetMapper delegate; + + protected SourceTargetMapperDecorator(SourceTargetMapper delegate) { + this.delegate = delegate; + } + + @Override + public Target mapSourceToTarget(Source source) { + return delegate.mapSourceToTarget( source ); + } +} diff --git a/integrationtest/src/test/resources/java8Test/src/main/java/org/mapstruct/ap/test/bugs/_603/Target.java b/integrationtest/src/test/resources/java8Test/src/main/java/org/mapstruct/ap/test/bugs/_603/Target.java new file mode 100644 index 000000000..2cb9f4e06 --- /dev/null +++ b/integrationtest/src/test/resources/java8Test/src/main/java/org/mapstruct/ap/test/bugs/_603/Target.java @@ -0,0 +1,40 @@ +/** + * Copyright 2012-2015 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.bugs._603; + +public class Target { + private String value1; + private String value2; + + public String getValue1() { + return value1; + } + + public void setValue1(String value1) { + this.value1 = value1; + } + + public String getValue2() { + return value2; + } + + public void setValue2(String value2) { + this.value2 = value2; + } +} diff --git a/integrationtest/src/test/resources/java8Test/src/test/java/org/mapstruct/ap/test/bugs/_603/Issue603Test.java b/integrationtest/src/test/resources/java8Test/src/test/java/org/mapstruct/ap/test/bugs/_603/Issue603Test.java new file mode 100644 index 000000000..f4f9e1177 --- /dev/null +++ b/integrationtest/src/test/resources/java8Test/src/test/java/org/mapstruct/ap/test/bugs/_603/Issue603Test.java @@ -0,0 +1,39 @@ +/** + * Copyright 2012-2015 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.bugs._603; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.fest.assertions.Assertions.assertThat; + +public class Issue603Test { + + @Test + public void shouldMapDataFromJava8Interface() { + + final Source source = new Source(); + + final Target target = SourceTargetMapper.INSTANCE.mapSourceToTarget( source ); + + assertThat( target ).isNotNull(); + assertThat( target.getValue1() ).isEqualTo( "foo" ); + assertThat( target.getValue2() ).isEqualTo( "bar" ); + } +} diff --git a/parent/pom.xml b/parent/pom.xml index 83669c0e0..883b8a847 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -238,7 +238,7 @@ org.apache.maven.plugins maven-checkstyle-plugin - 2.12.1 + 2.16 build-config/checkstyle.xml true @@ -252,7 +252,7 @@ specified as patterns within a source folder, so we can't exclude generated-sources altogether --> - *Prism.java,*/itest/jaxb/xsd/* + **/*Prism.java,*/itest/jaxb/xsd/* @@ -270,7 +270,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.1 + 3.3 1.6 1.6 diff --git a/processor/src/main/java/org/mapstruct/ap/internal/util/Executables.java b/processor/src/main/java/org/mapstruct/ap/internal/util/Executables.java index b542ce91f..3794ce9ed 100644 --- a/processor/src/main/java/org/mapstruct/ap/internal/util/Executables.java +++ b/processor/src/main/java/org/mapstruct/ap/internal/util/Executables.java @@ -18,9 +18,12 @@ */ package org.mapstruct.ap.internal.util; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; - +import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; @@ -46,6 +49,19 @@ import static org.mapstruct.ap.internal.util.SpecificCompilerWorkarounds.replace */ public class Executables { + private static final Method DEFAULT_METHOD; + + static { + Method method; + try { + method = ExecutableElement.class.getMethod( "isDefault" ); + } + catch ( NoSuchMethodException e ) { + method = null; + } + DEFAULT_METHOD = method; + } + private static final AccessorNamingStrategy ACCESSOR_NAMING_STRATEGY = Services.get( AccessorNamingStrategy.class, new DefaultAccessorNamingStrategy() @@ -80,6 +96,18 @@ public class Executables { return ACCESSOR_NAMING_STRATEGY.getPropertyName( getterOrSetterMethod ); } + public static boolean isDefaultMethod(ExecutableElement method) { + try { + return DEFAULT_METHOD != null && Boolean.TRUE.equals( DEFAULT_METHOD.invoke( method ) ); + } + catch ( IllegalAccessException e ) { + return false; + } + catch ( InvocationTargetException e ) { + return false; + } + } + /** * @param adderMethod the adder method * @return the 'element name' to which an adder method applies. If. e.g. an adder method is named @@ -159,7 +187,9 @@ public class Executables { List methodsToAdd, TypeElement parentType) { List safeToAdd = new ArrayList( methodsToAdd.size() ); for ( ExecutableElement toAdd : methodsToAdd ) { - if ( isNotObjectEquals( toAdd ) + if ( isNotStaticMethodInInterface( toAdd, parentType ) + && isNotInterfaceDefaultMethod( toAdd, parentType ) + && isNotObjectEquals( toAdd ) && wasNotYetOverridden( elementUtils, alreadyCollected, toAdd, parentType ) ) { safeToAdd.add( toAdd ); } @@ -168,6 +198,18 @@ public class Executables { alreadyCollected.addAll( 0, safeToAdd ); } + private static boolean isNotStaticMethodInInterface(ExecutableElement element, TypeElement parentType) { + return !( parentType.getKind().isInterface() && + element.getKind() == ElementKind.METHOD && + element.getModifiers().containsAll( Arrays.asList( Modifier.PUBLIC, Modifier.STATIC ) ) ); + } + + private static boolean isNotInterfaceDefaultMethod(ExecutableElement element, TypeElement parentType) { + return !( parentType.getKind().isInterface() && + element.getKind() == ElementKind.METHOD && + isDefaultMethod( element ) ); + } + /** * @param executable the executable to check *