#198 fixed, exceptions thrown by used Mappers aren't properly handled in the generated code

This commit is contained in:
sjaakd 2014-04-19 23:29:25 +02:00
parent 649d48b8c4
commit 0ed14cd691
16 changed files with 341 additions and 25 deletions

View File

@ -39,6 +39,7 @@ public class BeanMappingMethod extends MappingMethod {
private final List<PropertyMapping> propertyMappings;
private final FactoryMethod factoryMethod;
private final List<Type> exceptionTypes;
public BeanMappingMethod(SourceMethod method,
List<PropertyMapping> propertyMappings,
@ -46,6 +47,7 @@ public class BeanMappingMethod extends MappingMethod {
super( method );
this.propertyMappings = propertyMappings;
this.factoryMethod = factoryMethod;
this.exceptionTypes = method.getExceptionTypes();
}
public List<PropertyMapping> getPropertyMappings() {
@ -82,4 +84,7 @@ public class BeanMappingMethod extends MappingMethod {
return this.factoryMethod;
}
public List<Type> getExceptionTypes() {
return exceptionTypes;
}
}

View File

@ -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<Type> exceptionTypesToExclude;
public LocalVarWrapper( Assignment decoratedAssignment, List<Type> exceptionTypesToExclude ) {
super( decoratedAssignment );
this.exceptionTypesToExclude = exceptionTypesToExclude;
}
@Override
public List<Type> getExceptionTypes() {
List<Type> result = super.getExceptionTypes();
for (Type exceptionTypeToExclude : exceptionTypesToExclude) {
result.remove( exceptionTypeToExclude );
}
return result;
}
}

View File

@ -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<Type> importTypes;
private final List<Type> exceptionTypes;
/**
* In case this reference targets a built-in method, allows to pass specific context information to the invoked
@ -74,6 +76,7 @@ public class MethodReference extends MappingMethod implements Assignment, Factor
this.importTypes = targetType == null ?
Collections.<Type>emptySet() :
Collections.<Type>singleton( targetType );
this.exceptionTypes = method.getExceptionTypes();
}
public MethodReference(BuiltInMethod method, ConversionContext contextParam) {
@ -81,6 +84,7 @@ public class MethodReference extends MappingMethod implements Assignment, Factor
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<Type> getExceptionTypes() {
List<Type> exceptions = Collections.emptyList();
List<Type> exceptions = new ArrayList<Type>();
exceptions.addAll( exceptionTypes );
if ( assignment != null ) {
exceptions.addAll( assignment.getExceptionTypes() );
}

View File

@ -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<Type> exceptionTypesToExclude;
public SetterWrapper( Assignment decoratedAssignment, List<Type> exceptionTypesToExclude ) {
super( decoratedAssignment );
this.exceptionTypesToExclude = exceptionTypesToExclude;
}
@Override
public List<Type> getExceptionTypes() {
List<Type> result = super.getExceptionTypes();
for (Type exceptionTypeToExclude : exceptionTypesToExclude) {
result.remove( exceptionTypeToExclude );
}
return result;
}
}

View File

@ -241,6 +241,14 @@ public class TypeFactory {
return getType( method.getReturnType() );
}
public List<Type> getThrownTypes(ExecutableElement method) {
List<Type> thrownTypes = new ArrayList<Type>();
for (TypeMirror exceptionType : method.getThrownTypes() ) {
thrownTypes.add( getType( exceptionType ) );
}
return thrownTypes;
}
private List<Type> getTypeParameters(TypeMirror mirror) {
if ( mirror.getKind() != TypeKind.DECLARED ) {
return java.util.Collections.emptyList();

View File

@ -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<Type> exceptionTypes;
private Map<String, List<Mapping>> mappings;
private IterableMapping iterableMapping;
@ -58,7 +60,9 @@ public class SourceMethod implements Method {
private boolean configuredByReverseMappingMethod = false;
public static SourceMethod forMethodRequiringImplementation(ExecutableElement executable,
List<Parameter> parameters, Type returnType,
List<Parameter> parameters,
Type returnType,
List<Type> exceptionTypes,
Map<String, List<Mapping>> 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<Parameter> parameters, Type returnType, Types typeUtils) {
List<Parameter> parameters, Type returnType,
List<Type> exceptionTypes, Types typeUtils) {
return new SourceMethod(
declaringMapper,
executable,
parameters,
returnType,
exceptionTypes,
Collections.<String, List<Mapping>> emptyMap(),
null,
null,
typeUtils
);
typeUtils );
}
public static SourceMethod forFactoryMethod(Type declaringMapper, ExecutableElement executable, Type returnType,
Types typeUtils) {
List<Type> exceptionTypes, Types typeUtils) {
return new SourceMethod(
declaringMapper,
executable,
Collections.<Parameter> emptyList(),
returnType,
exceptionTypes,
Collections.<String, List<Mapping>> emptyMap(),
null,
null,
typeUtils
);
typeUtils );
}
private SourceMethod(Type declaringMapper, ExecutableElement executable, List<Parameter> parameters,
Type returnType, Map<String, List<Mapping>> mappings, IterableMapping iterableMapping,
MapMapping mapMapping, Types typeUtils) {
Type returnType, List<Type> exceptionTypes, Map<String, List<Mapping>> 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 <code>true</code>, iff the parameter list contains a parameter annotated with {@code @TargetType}
*/
public static boolean containsTargetTypeParameter(List<Parameter> parameters) {
@ -345,4 +350,8 @@ public class SourceMethod implements Method {
return false;
}
public List<Type> getExceptionTypes() {
return exceptionTypes;
}
}

View File

@ -670,7 +670,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
}
// target accessor is setter, so decorate assigmment as setter
assignment = new SetterWrapper( assignment );
assignment = new SetterWrapper( assignment, method.getExceptionTypes() );
// decorate assigment with null check of source can be null (is not primitive)
if ( !sourceType.isPrimitive() ) {
@ -736,7 +736,7 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
}
// target accessor is setter, so decorate assigmment as setter
assignment = new SetterWrapper( assignment );
assignment = new SetterWrapper( assignment, method.getExceptionTypes() );
FactoryMethod factoryMethod = getFactoryMethod( mapperReferences, methods, method.getReturnType() );
return new IterableMappingMethod( method, assignment, factoryMethod );
@ -807,8 +807,8 @@ public class MapperCreationProcessor implements ModelElementProcessor<List<Sourc
FactoryMethod factoryMethod = getFactoryMethod( mapperReferences, methods, method.getReturnType() );
keyAssignment = new LocalVarWrapper( keyAssignment );
valueAssignment = new LocalVarWrapper( valueAssignment );
keyAssignment = new LocalVarWrapper( keyAssignment, method.getExceptionTypes() );
valueAssignment = new LocalVarWrapper( valueAssignment, method.getExceptionTypes() );
return new MapMappingMethod( method, keyAssignment, valueAssignment, factoryMethod );
}

View File

@ -145,6 +145,7 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
boolean mapperRequiresImplementation) {
List<Parameter> parameters = typeFactory.getParameters( method );
Type returnType = typeFactory.getReturnType( method );
List<Type> 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<Void, Lis
method,
parameters,
returnType,
exceptionTypes,
getMappings( method ),
IterableMapping.fromPrism( IterableMappingPrism.getInstanceOn( method ) ),
MapMapping.fromPrism( MapMappingPrism.getInstanceOn( method ) ),
@ -188,6 +190,7 @@ public class MethodRetrievalProcessor implements ModelElementProcessor<Void, Lis
method,
parameters,
returnType,
exceptionTypes,
typeUtils
);
}

View File

@ -19,7 +19,7 @@
-->
@Override
<#lt>${accessibility.keyword} <@includeModel object=returnType/> ${name}(<#list parameters as param><@includeModel object=param/><#if param_has_next>, </#if></#list>) {
<#lt>${accessibility.keyword} <@includeModel object=returnType/> ${name}(<#list parameters as param><@includeModel object=param/><#if param_has_next>, </#if></#list>)<@exceptions/> {
if ( <#list sourceParameters as sourceParam>${sourceParam.name} == null<#if sourceParam_has_next> && </#if></#list> ) {
return<#if returnType.name != "void"> null</#if>;
}
@ -43,3 +43,4 @@
return ${resultName};
</#if>
}
<#macro exceptions><#if (exceptionTypes?size > 0)> throws </#if><#list exceptionTypes as exceptionType>${exceptionType.name}<#if exceptionType_has_next>, </#if></#list></#macro>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 {
}

View File

@ -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 {
}