From 0ed14cd691177f1288344c678c385de0ae668f65 Mon Sep 17 00:00:00 2001 From: sjaakd Date: Sat, 19 Apr 2014 23:29:25 +0200 Subject: [PATCH] #198 fixed, exceptions thrown by used Mappers aren't properly handled in the generated code --- .../mapstruct/ap/model/BeanMappingMethod.java | 5 ++ .../ap/model/assignment/LocalVarWrapper.java | 16 ++++- .../ap/model/assignment/MethodReference.java | 9 ++- .../ap/model/assignment/SetterWrapper.java | 16 ++++- .../ap/model/common/TypeFactory.java | 8 +++ .../ap/model/source/SourceMethod.java | 39 +++++++----- .../ap/processor/MapperCreationProcessor.java | 8 +-- .../processor/MethodRetrievalProcessor.java | 3 + ...g.mapstruct.ap.model.BeanMappingMethod.ftl | 5 +- .../ap/test/exceptions/ExceptionTest.java | 60 +++++++++++++++++++ .../test/exceptions/ExceptionTestMapper.java | 36 +++++++++++ .../mapstruct/ap/test/exceptions/Source.java | 36 +++++++++++ .../test/exceptions/SourceTargetMapper.java | 36 +++++++++++ .../mapstruct/ap/test/exceptions/Target.java | 37 ++++++++++++ .../ap/test/exceptions/TestException1.java | 26 ++++++++ .../ap/test/exceptions/TestException2.java | 26 ++++++++ 16 files changed, 341 insertions(+), 25 deletions(-) create mode 100644 processor/src/test/java/org/mapstruct/ap/test/exceptions/ExceptionTest.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/exceptions/ExceptionTestMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/exceptions/Source.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/exceptions/SourceTargetMapper.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/exceptions/Target.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/exceptions/TestException1.java create mode 100644 processor/src/test/java/org/mapstruct/ap/test/exceptions/TestException2.java diff --git a/processor/src/main/java/org/mapstruct/ap/model/BeanMappingMethod.java b/processor/src/main/java/org/mapstruct/ap/model/BeanMappingMethod.java index 49bbbf5d3..026644397 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/BeanMappingMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/model/BeanMappingMethod.java @@ -39,6 +39,7 @@ public class BeanMappingMethod extends MappingMethod { private final List propertyMappings; private final FactoryMethod factoryMethod; + private final List exceptionTypes; public BeanMappingMethod(SourceMethod method, List propertyMappings, @@ -46,6 +47,7 @@ public class BeanMappingMethod extends MappingMethod { super( method ); this.propertyMappings = propertyMappings; this.factoryMethod = factoryMethod; + this.exceptionTypes = method.getExceptionTypes(); } public List getPropertyMappings() { @@ -82,4 +84,7 @@ public class BeanMappingMethod extends MappingMethod { return this.factoryMethod; } + public List getExceptionTypes() { + return exceptionTypes; + } } diff --git a/processor/src/main/java/org/mapstruct/ap/model/assignment/LocalVarWrapper.java b/processor/src/main/java/org/mapstruct/ap/model/assignment/LocalVarWrapper.java index 60a0b9764..34b2d76c4 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/assignment/LocalVarWrapper.java +++ b/processor/src/main/java/org/mapstruct/ap/model/assignment/LocalVarWrapper.java @@ -18,7 +18,9 @@ */ package org.mapstruct.ap.model.assignment; +import java.util.List; import org.mapstruct.ap.model.Assignment; +import org.mapstruct.ap.model.common.Type; /** * Decorates an assignment as local variable. @@ -27,7 +29,19 @@ import org.mapstruct.ap.model.Assignment; */ public class LocalVarWrapper extends AssignmentWrapper { - public LocalVarWrapper( Assignment decoratedAssignment ) { + private final List exceptionTypesToExclude; + + public LocalVarWrapper( Assignment decoratedAssignment, List exceptionTypesToExclude ) { super( decoratedAssignment ); + this.exceptionTypesToExclude = exceptionTypesToExclude; + } + + @Override + public List getExceptionTypes() { + List result = super.getExceptionTypes(); + for (Type exceptionTypeToExclude : exceptionTypesToExclude) { + result.remove( exceptionTypeToExclude ); + } + return result; } } diff --git a/processor/src/main/java/org/mapstruct/ap/model/assignment/MethodReference.java b/processor/src/main/java/org/mapstruct/ap/model/assignment/MethodReference.java index 9d18cbec0..3d809e97c 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/assignment/MethodReference.java +++ b/processor/src/main/java/org/mapstruct/ap/model/assignment/MethodReference.java @@ -18,6 +18,7 @@ */ package org.mapstruct.ap.model.assignment; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; @@ -41,6 +42,7 @@ public class MethodReference extends MappingMethod implements Assignment, Factor private final MapperReference declaringMapper; private final Set importTypes; + private final List exceptionTypes; /** * In case this reference targets a built-in method, allows to pass specific context information to the invoked @@ -74,13 +76,15 @@ public class MethodReference extends MappingMethod implements Assignment, Factor this.importTypes = targetType == null ? Collections.emptySet() : Collections.singleton( targetType ); - } + this.exceptionTypes = method.getExceptionTypes(); + } public MethodReference(BuiltInMethod method, ConversionContext contextParam) { super( method ); this.declaringMapper = null; this.contextParam = method.getContextParameter( contextParam ); this.importTypes = Collections.emptySet(); + this.exceptionTypes = Collections.emptyList(); } public MapperReference getDeclaringMapper() { @@ -132,7 +136,8 @@ public class MethodReference extends MappingMethod implements Assignment, Factor @Override public List getExceptionTypes() { - List exceptions = Collections.emptyList(); + List exceptions = new ArrayList(); + exceptions.addAll( exceptionTypes ); if ( assignment != null ) { exceptions.addAll( assignment.getExceptionTypes() ); } diff --git a/processor/src/main/java/org/mapstruct/ap/model/assignment/SetterWrapper.java b/processor/src/main/java/org/mapstruct/ap/model/assignment/SetterWrapper.java index 17a602b46..d94ec9fb2 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/assignment/SetterWrapper.java +++ b/processor/src/main/java/org/mapstruct/ap/model/assignment/SetterWrapper.java @@ -18,7 +18,9 @@ */ package org.mapstruct.ap.model.assignment; +import java.util.List; import org.mapstruct.ap.model.Assignment; +import org.mapstruct.ap.model.common.Type; /** * Wraps the assignment in a target setter. @@ -27,7 +29,19 @@ import org.mapstruct.ap.model.Assignment; */ public class SetterWrapper extends AssignmentWrapper { - public SetterWrapper( Assignment decoratedAssignment ) { + private final List exceptionTypesToExclude; + + public SetterWrapper( Assignment decoratedAssignment, List exceptionTypesToExclude ) { super( decoratedAssignment ); + this.exceptionTypesToExclude = exceptionTypesToExclude; + } + + @Override + public List getExceptionTypes() { + List result = super.getExceptionTypes(); + for (Type exceptionTypeToExclude : exceptionTypesToExclude) { + result.remove( exceptionTypeToExclude ); + } + return result; } } diff --git a/processor/src/main/java/org/mapstruct/ap/model/common/TypeFactory.java b/processor/src/main/java/org/mapstruct/ap/model/common/TypeFactory.java index 8e18c801e..d1a037078 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/common/TypeFactory.java +++ b/processor/src/main/java/org/mapstruct/ap/model/common/TypeFactory.java @@ -241,6 +241,14 @@ public class TypeFactory { return getType( method.getReturnType() ); } + public List getThrownTypes(ExecutableElement method) { + List thrownTypes = new ArrayList(); + for (TypeMirror exceptionType : method.getThrownTypes() ) { + thrownTypes.add( getType( exceptionType ) ); + } + return thrownTypes; + } + private List getTypeParameters(TypeMirror mirror) { if ( mirror.getKind() != TypeKind.DECLARED ) { return java.util.Collections.emptyList(); diff --git a/processor/src/main/java/org/mapstruct/ap/model/source/SourceMethod.java b/processor/src/main/java/org/mapstruct/ap/model/source/SourceMethod.java index f9ec44890..9b302634a 100644 --- a/processor/src/main/java/org/mapstruct/ap/model/source/SourceMethod.java +++ b/processor/src/main/java/org/mapstruct/ap/model/source/SourceMethod.java @@ -22,6 +22,7 @@ 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 javax.lang.model.util.Types; @@ -50,6 +51,7 @@ public class SourceMethod implements Method { private final Type returnType; private final Accessibility accessibility; private final Types typeUtils; + private final List exceptionTypes; private Map> mappings; private IterableMapping iterableMapping; @@ -58,7 +60,9 @@ public class SourceMethod implements Method { private boolean configuredByReverseMappingMethod = false; public static SourceMethod forMethodRequiringImplementation(ExecutableElement executable, - List parameters, Type returnType, + List parameters, + Type returnType, + List exceptionTypes, Map> mappings, IterableMapping iterableMapping, MapMapping mapMapping, Types typeUtils) { @@ -68,50 +72,52 @@ public class SourceMethod implements Method { executable, parameters, returnType, + exceptionTypes, mappings, iterableMapping, mapMapping, - typeUtils - ); + typeUtils ); } public static SourceMethod forReferencedMethod(Type declaringMapper, ExecutableElement executable, - List parameters, Type returnType, Types typeUtils) { + List parameters, Type returnType, + List exceptionTypes, Types typeUtils) { return new SourceMethod( declaringMapper, executable, parameters, returnType, - Collections.>emptyMap(), + exceptionTypes, + Collections.> emptyMap(), null, null, - typeUtils - ); + typeUtils ); } public static SourceMethod forFactoryMethod(Type declaringMapper, ExecutableElement executable, Type returnType, - Types typeUtils) { + List exceptionTypes, Types typeUtils) { return new SourceMethod( declaringMapper, executable, - Collections.emptyList(), + Collections. emptyList(), returnType, - Collections.>emptyMap(), + exceptionTypes, + Collections.> emptyMap(), null, null, - typeUtils - ); + typeUtils ); } private SourceMethod(Type declaringMapper, ExecutableElement executable, List parameters, - Type returnType, Map> mappings, IterableMapping iterableMapping, - MapMapping mapMapping, Types typeUtils) { + Type returnType, List exceptionTypes, Map> mappings, + IterableMapping iterableMapping, MapMapping mapMapping, Types typeUtils) { this.declaringMapper = declaringMapper; this.executable = executable; this.parameters = parameters; this.returnType = returnType; + this.exceptionTypes = exceptionTypes; this.mappings = mappings; this.iterableMapping = iterableMapping; this.mapMapping = mapMapping; @@ -333,7 +339,6 @@ public class SourceMethod implements Method { /** * @param parameters the parameter list to check - * * @return true, iff the parameter list contains a parameter annotated with {@code @TargetType} */ public static boolean containsTargetTypeParameter(List parameters) { @@ -345,4 +350,8 @@ public class SourceMethod implements Method { return false; } + + public List getExceptionTypes() { + return exceptionTypes; + } } diff --git a/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java b/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java index 4e8473edf..0a629d1a0 100644 --- a/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java +++ b/processor/src/main/java/org/mapstruct/ap/processor/MapperCreationProcessor.java @@ -670,7 +670,7 @@ public class MapperCreationProcessor implements ModelElementProcessor parameters = typeFactory.getParameters( method ); Type returnType = typeFactory.getReturnType( method ); + List exceptionTypes = typeFactory.getThrownTypes( method ); //add method with property mappings if an implementation needs to be generated boolean methodRequiresImplementation = method.getModifiers().contains( Modifier.ABSTRACT ); @@ -170,6 +171,7 @@ public class MethodRetrievalProcessor implements ModelElementProcessor @Override -<#lt>${accessibility.keyword} <@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>, )<@exceptions/> { if ( <#list sourceParameters as sourceParam>${sourceParam.name} == null<#if sourceParam_has_next> && ) { return<#if returnType.name != "void"> null; } @@ -42,4 +42,5 @@ return ${resultName}; -} \ No newline at end of file +} +<#macro exceptions><#if (exceptionTypes?size > 0)> throws <#list exceptionTypes as exceptionType>${exceptionType.name}<#if exceptionType_has_next>, diff --git a/processor/src/test/java/org/mapstruct/ap/test/exceptions/ExceptionTest.java b/processor/src/test/java/org/mapstruct/ap/test/exceptions/ExceptionTest.java new file mode 100644 index 000000000..fbca59146 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/exceptions/ExceptionTest.java @@ -0,0 +1,60 @@ +/** + * 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.exceptions; + + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mapstruct.ap.testutil.IssueKey; +import org.mapstruct.ap.testutil.WithClasses; +import org.mapstruct.ap.testutil.runner.AnnotationProcessorTestRunner; + +/** + * + * @author Sjaak Derksen + */ +@WithClasses( { + Source.class, + Target.class, + SourceTargetMapper.class, + ExceptionTestMapper.class, + TestException1.class, + TestException2.class } ) +@RunWith( AnnotationProcessorTestRunner.class ) +public class ExceptionTest { + + @Test(expected = RuntimeException.class) + @IssueKey( "198" ) + public void shouldThrowRuntime() throws TestException2 { + Source source = new Source(); + source.setSize( 1 ); + SourceTargetMapper sourceTargetMapper = SourceTargetMapper.INSTANCE; + sourceTargetMapper.sourceToTarget( source ); + } + + @Test(expected = TestException2.class) + @IssueKey( "198" ) + public void shouldThrowTestException2() throws TestException2 { + Source source = new Source(); + source.setSize( 2 ); + SourceTargetMapper sourceTargetMapper = SourceTargetMapper.INSTANCE; + sourceTargetMapper.sourceToTarget( source ); + } + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/exceptions/ExceptionTestMapper.java b/processor/src/test/java/org/mapstruct/ap/test/exceptions/ExceptionTestMapper.java new file mode 100644 index 000000000..811538eb5 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/exceptions/ExceptionTestMapper.java @@ -0,0 +1,36 @@ +/** + * 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.exceptions; + +/** + * @author Sjaak Derksen + * + */ +public class ExceptionTestMapper { + + public Long toLong(int size) throws TestException1, TestException2 { + if ( size == 1 ) { + throw new TestException1(); + } + else if ( size == 2 ) { + throw new TestException2(); + } + return new Long(size); + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/exceptions/Source.java b/processor/src/test/java/org/mapstruct/ap/test/exceptions/Source.java new file mode 100644 index 000000000..1f8da932e --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/exceptions/Source.java @@ -0,0 +1,36 @@ +/** + * 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.exceptions; + +/** + * + * @author Sjaak Derksen + */ +public class Source { + + private int size; + + public int getSize() { + return size; + } + + public void setSize( int size ) { + this.size = size; + } +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/exceptions/SourceTargetMapper.java b/processor/src/test/java/org/mapstruct/ap/test/exceptions/SourceTargetMapper.java new file mode 100644 index 000000000..7fbd1a8b7 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/exceptions/SourceTargetMapper.java @@ -0,0 +1,36 @@ +/** + * 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.exceptions; + + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +/** + * + * @author Sjaak Derksen + */ +@Mapper( uses = ExceptionTestMapper.class ) +public interface SourceTargetMapper { + + SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class ); + + Target sourceToTarget(Source source) throws TestException2; + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/exceptions/Target.java b/processor/src/test/java/org/mapstruct/ap/test/exceptions/Target.java new file mode 100644 index 000000000..d71f8998b --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/exceptions/Target.java @@ -0,0 +1,37 @@ +/** + * 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.exceptions; + +/** + * + * @author Sjaak Derksen + */ +public class Target { + + private Long size; + + public Long getSize() { + return size; + } + + public void setSize(Long size) { + this.size = size; + } + +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/exceptions/TestException1.java b/processor/src/test/java/org/mapstruct/ap/test/exceptions/TestException1.java new file mode 100644 index 000000000..e8b752fea --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/exceptions/TestException1.java @@ -0,0 +1,26 @@ +/** + * 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.exceptions; + +/** + * + * @author Sjaak Derksen + */ +public class TestException1 extends Exception { +} diff --git a/processor/src/test/java/org/mapstruct/ap/test/exceptions/TestException2.java b/processor/src/test/java/org/mapstruct/ap/test/exceptions/TestException2.java new file mode 100644 index 000000000..f4b8aa014 --- /dev/null +++ b/processor/src/test/java/org/mapstruct/ap/test/exceptions/TestException2.java @@ -0,0 +1,26 @@ +/** + * 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.exceptions; + +/** + * + * @author Sjaak Derksen + */ +public class TestException2 extends Exception { +}