#35 Raising warning in case of unmapped target properties

This commit is contained in:
Gunnar Morling 2013-06-09 15:12:54 +02:00
parent 895a715727
commit bf5a4303b6
14 changed files with 555 additions and 36 deletions

View File

@ -90,7 +90,9 @@
<module name="AvoidStarImport"/>
<module name="IllegalImport"/> <!-- defaults to sun.* packages -->
<module name="RedundantImport"/>
<module name="UnusedImports"/>
<module name="UnusedImports">
<property name="processJavadoc" value="true"/>
</module>
<!-- Checks for Size Violations. -->

View File

@ -39,4 +39,12 @@ public @interface Mapper {
* @return The mapper types used by this mapper.
*/
Class<?>[] uses() default { };
/**
* How unmapped properties of the target type of a mapping should be
* reported.
*
* @return The reporting policy for unmapped target properties.
*/
ReportingPolicy unmappedTargetPolicy() default ReportingPolicy.WARN;
}

View File

@ -0,0 +1,46 @@
/**
* Copyright 2012-2013 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;
import javax.tools.Diagnostic.Kind;
/**
* Policy for reporting issues occurring during the generation of a mapper
* implementation.
*
* @author Gunnar Morling
*/
public enum ReportingPolicy {
/**
* No report will be created for the given issue.
*/
IGNORE,
/**
* A report with {@link Kind#WARNING} will be created for the given issue.
*/
WARN,
/**
* A report with {@link Kind#ERROR} will be created for the given issue,
* causing the compilation to fail.
*/
ERROR;
}

View File

@ -20,8 +20,8 @@ package org.mapstruct.ap;
import java.beans.Introspector;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
@ -32,6 +32,7 @@ import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementVisitor;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
@ -50,6 +51,7 @@ import org.mapstruct.ap.model.Mapper;
import org.mapstruct.ap.model.MappingMethod;
import org.mapstruct.ap.model.Options;
import org.mapstruct.ap.model.PropertyMapping;
import org.mapstruct.ap.model.ReportingPolicy;
import org.mapstruct.ap.model.Type;
import org.mapstruct.ap.model.source.MappedProperty;
import org.mapstruct.ap.model.source.Mapping;
@ -57,6 +59,7 @@ import org.mapstruct.ap.model.source.Method;
import org.mapstruct.ap.model.source.Parameter;
import org.mapstruct.ap.util.Executables;
import org.mapstruct.ap.util.Filters;
import org.mapstruct.ap.util.Strings;
import org.mapstruct.ap.util.TypeUtil;
import org.mapstruct.ap.writer.ModelWriter;
@ -133,8 +136,14 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
}
private Mapper retrieveModel(TypeElement element) {
List<Method> methods = retrieveMethods( null, element );
List<BeanMapping> mappings = getMappings( methods );
//1.) build up "source" model
List<Method> methods = retrieveMethods( element, true );
//2.) build up aggregated "target" model
List<BeanMapping> mappings = getMappings(
methods,
ReportingPolicy.valueOf( MapperPrism.getInstanceOn( element ).unmappedTargetPolicy() )
);
List<Type> usedMapperTypes = getUsedMapperTypes( element );
Mapper mapper = new Mapper(
@ -149,7 +158,8 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
return mapper;
}
private List<BeanMapping> getMappings(List<Method> methods) {
private List<BeanMapping> getMappings(List<Method> methods,
ReportingPolicy unmappedTargetPolicy) {
Conversions conversions = new Conversions( elementUtils, typeUtils, typeUtil );
List<BeanMapping> mappings = new ArrayList<BeanMapping>();
@ -181,8 +191,13 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
}
List<PropertyMapping> propertyMappings = new ArrayList<PropertyMapping>();
Set<String> mappedSourceProperties = new HashSet<String>();
Set<String> mappedTargetProperties = new HashSet<String>();
for ( MappedProperty property : method.getMappedProperties() ) {
mappedSourceProperties.add( property.getSourceName() );
mappedTargetProperties.add( property.getTargetName() );
Method propertyMappingMethod = getPropertyMappingMethod( methods, property );
Method reversePropertyMappingMethod = getReversePropertyMappingMethod( methods, property );
Conversion conversion = conversions.getConversion( property.getSourceType(), property.getTargetType() );
@ -229,6 +244,23 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
boolean isIterableMapping = method.getSourceType().isIterableType() && method.getTargetType()
.isIterableType();
if ( mappingMethod.isGenerationRequired() && !isIterableMapping ) {
reportErrorForUnmappedTargetPropertiesIfRequired(
method.getExecutable(),
unmappedTargetPolicy,
method.getTargetProeprties(),
mappedTargetProperties
);
}
if ( reverseMappingMethod != null && reverseMappingMethod.isGenerationRequired() && !isIterableMapping ) {
reportErrorForUnmappedTargetPropertiesIfRequired(
rawReverseMappingMethod.getExecutable(),
unmappedTargetPolicy,
method.getSourceProperties(),
mappedSourceProperties
);
}
String toConversionString = null;
String fromConversionString = null;
@ -262,6 +294,25 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
return mappings;
}
private void reportErrorForUnmappedTargetPropertiesIfRequired(ExecutableElement method,
ReportingPolicy unmappedTargetPolicy,
Set<String> targetProperties,
Set<String> mappedTargetProperties) {
if ( targetProperties.size() > mappedTargetProperties.size() && unmappedTargetPolicy.requiresReport() ) {
targetProperties.removeAll( mappedTargetProperties );
printMessage(
unmappedTargetPolicy,
MessageFormat.format(
"Unmapped target {0,choice,1#property|1<properties}: \"{1}\"",
targetProperties.size(),
Strings.join( targetProperties, ", " )
),
method
);
}
}
private void reportErrorIfPropertyCanNotBeMapped(Method method, Method reverseMethod, MappedProperty property,
Method propertyMappingMethod, Method reversePropertyMappingMethod,
Conversion conversion) {
@ -379,15 +430,32 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
return null;
}
private List<Method> retrieveMethods(Type declaringMapper, Element element) {
/**
* Retrieves the mapping methods declared by the given mapper type.
*
* @param element The type of interest
* @param implementationRequired Whether an implementation of this type must be generated or
* not. {@code true} if the type is the currently processed
* mapper interface, {@code false} if the given type is one
* referred to via {@code Mapper#uses()}.
*
* @return All mapping methods declared by the given type
*/
private List<Method> retrieveMethods(TypeElement element, boolean implementationRequired) {
List<Method> methods = new ArrayList<Method>();
MapperPrism mapperPrism = implementationRequired ? MapperPrism.getInstanceOn( element ) : null;
//TODO Extract to separate method
for ( ExecutableElement method : methodsIn( element.getEnclosedElements() ) ) {
Parameter parameter = retrieveParameter( method );
Type returnType = retrieveReturnType( method );
Element returnTypeElement = typeUtils.asElement( method.getReturnType() );
Element parameterElement = typeUtils.asElement( method.getParameters().get( 0 ).asType() );
boolean mappingErroneous = false;
if ( declaringMapper == null ) {
if ( implementationRequired ) {
if ( parameter.getType().isIterableType() && !returnType.isIterableType() ) {
reportError( "Can't generate mapping method from iterable type to non-iterable type.", method );
mappingErroneous = true;
@ -410,30 +478,48 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
}
}
//retrieve property mappings if an implementation for the method needs to be generated
List<MappedProperty> properties = declaringMapper == null ? retrieveMappedProperties( method ) : Collections
.<MappedProperty>emptyList();
//add method with property mappings if an implementation needs to be generated
if ( implementationRequired ) {
Set<String> sourceProperties = Executables.getPropertyNames(
Filters.getterMethodsIn( parameterElement.getEnclosedElements() )
);
Set<String> targetProperties = Executables.getPropertyNames(
Filters.setterMethodsIn( returnTypeElement.getEnclosedElements() )
);
methods.add(
new Method(
declaringMapper,
Method.forMethodRequiringImplementation(
method,
parameter.getName(),
parameter.getType(),
returnType,
properties
sourceProperties,
targetProperties,
retrieveMappedProperties( method, sourceProperties, targetProperties )
)
);
}
//otherwise add reference to existing mapper method
else {
methods.add(
Method.forReferencedMethod(
typeUtil.getType( typeUtils.getDeclaredType( element ) ),
method,
parameter.getName(),
parameter.getType(),
returnType
)
);
}
}
MapperPrism mapperPrism = MapperPrism.getInstanceOn( element );
if ( mapperPrism != null ) {
//Add all methods of used mappers in order to reference them in the aggregated model
if ( implementationRequired ) {
for ( TypeMirror usedMapper : mapperPrism.uses() ) {
methods.addAll(
retrieveMethods(
typeUtil.retrieveType( usedMapper ),
( (DeclaredType) usedMapper ).asElement()
(TypeElement) ( (DeclaredType) usedMapper ).asElement(),
false
)
);
}
@ -448,10 +534,14 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
* method.
*
* @param method The method of interest
* @param targetProperties
* @param sourceProperties
*
* @return All mapped properties for the given method
*/
private List<MappedProperty> retrieveMappedProperties(ExecutableElement method) {
private List<MappedProperty> retrieveMappedProperties(ExecutableElement method, Set<String> sourceProperties,
Set<String> targetProperties) {
Map<String, Mapping> mappings = getMappings( method );
TypeElement returnTypeElement = (TypeElement) typeUtils.asElement( method.getReturnType() );
@ -472,7 +562,7 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
elementUtils.getAllMembers( returnTypeElement )
);
reportErrorIfMappedPropertiesDontExist( method, mappings, sourceGetters, targetSetters );
reportErrorIfMappedPropertiesDontExist( method, sourceProperties, targetProperties, mappings );
for ( ExecutableElement getterMethod : sourceGetters ) {
String sourcePropertyName = Executables.getPropertyName( getterMethod );
@ -509,12 +599,9 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
return properties;
}
private void reportErrorIfMappedPropertiesDontExist(ExecutableElement method, Map<String, Mapping> mappings,
List<ExecutableElement> sourceGetters,
List<ExecutableElement> targetSetters) {
Set<String> sourcePropertyNames = Executables.getPropertyNames( sourceGetters );
Set<String> targetPropertyNames = Executables.getPropertyNames( targetSetters );
private void reportErrorIfMappedPropertiesDontExist(ExecutableElement method, Set<String> sourcePropertyNames,
Set<String> targetPropertyNames,
Map<String, Mapping> mappings) {
for ( Mapping mappedProperty : mappings.values() ) {
if ( !sourcePropertyNames.contains( mappedProperty.getSourceName() ) ) {
@ -594,4 +681,11 @@ public class MapperGenerationVisitor extends ElementKindVisitor6<Void, Void> {
.printMessage( Kind.ERROR, message, element, annotationMirror, annotationValue );
mappingErroneous = true;
}
private void printMessage(ReportingPolicy reportingPolicy, String message, Element element) {
processingEnvironment.getMessager().printMessage( reportingPolicy.getDiagnosticKind(), message, element );
if ( reportingPolicy.failsBuild() ) {
mappingErroneous = true;
}
}
}

View File

@ -0,0 +1,55 @@
/**
* Copyright 2012-2013 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;
import javax.tools.Diagnostic;
import javax.tools.Diagnostic.Kind;
/**
* Possible issue reporting policies. Duplicates the enum of the same name from
* the core module as this can't be referenced here.
*
* @author Gunnar Morling
*/
public enum ReportingPolicy {
IGNORE( null, false, false ), WARN( Kind.WARNING, true, false ), ERROR( Kind.ERROR, true, true );
private final Diagnostic.Kind diagnosticKind;
private final boolean requiresReport;
private final boolean failsBuild;
private ReportingPolicy(Diagnostic.Kind diagnosticKind, boolean requiresReport, boolean failsBuild) {
this.requiresReport = requiresReport;
this.diagnosticKind = diagnosticKind;
this.failsBuild = failsBuild;
}
public Diagnostic.Kind getDiagnosticKind() {
return diagnosticKind;
}
public boolean requiresReport() {
return requiresReport;
}
public boolean failsBuild() {
return failsBuild;
}
}

View File

@ -18,7 +18,9 @@
*/
package org.mapstruct.ap.model.source;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.lang.model.element.ExecutableElement;
import org.mapstruct.ap.model.Type;
@ -36,18 +38,64 @@ public class Method {
private final String parameterName;
private final Type sourceType;
private final Type targetType;
private Set<String> sourceProperties;
private Set<String> targetProeprties;
private final List<MappedProperty> mappedProperties;
public Method(Type declaringMapper, ExecutableElement executable, String parameterName, Type sourceType,
Type targetType, List<MappedProperty> mappedProperties) {
public static Method forMethodRequiringImplementation(ExecutableElement executable, String parameterName,
Type sourceType,
Type targetType, Set<String> sourceProperties,
Set<String> targetProperties,
List<MappedProperty> mappedProperties) {
return new Method(
null,
executable,
parameterName,
sourceType,
targetType,
sourceProperties,
targetProperties,
mappedProperties
);
}
public static Method forReferencedMethod(Type declaringMapper, ExecutableElement executable, String parameterName,
Type sourceType,
Type targetType) {
return new Method(
declaringMapper,
executable,
parameterName,
sourceType,
targetType,
Collections.<String>emptySet(),
Collections.<String>emptySet(),
Collections.<MappedProperty>emptyList()
);
}
private Method(Type declaringMapper, ExecutableElement executable, String parameterName, Type sourceType,
Type targetType, Set<String> sourceProperties, Set<String> targetProperties,
List<MappedProperty> mappedProperties) {
this.declaringMapper = declaringMapper;
this.executable = executable;
this.parameterName = parameterName;
this.sourceType = sourceType;
this.targetType = targetType;
this.sourceProperties = sourceProperties;
this.targetProeprties = targetProperties;
this.mappedProperties = mappedProperties;
}
/**
* Returns the mapper type declaring this method if it is not declared by
* the mapper interface currently processed but by another mapper imported
* via {@code Mapper#users()}.
*
* @return The declaring mapper type
*/
public Type getDeclaringMapper() {
return declaringMapper;
}
@ -72,6 +120,14 @@ public class Method {
return targetType;
}
public Set<String> getSourceProperties() {
return sourceProperties;
}
public Set<String> getTargetProeprties() {
return targetProeprties;
}
public List<MappedProperty> getMappedProperties() {
return mappedProperties;
}

View File

@ -22,7 +22,6 @@ import java.beans.Introspector;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.type.TypeKind;

View File

@ -18,6 +18,11 @@
*/
package org.mapstruct.ap.util;
/**
* Helper class for dealing with strings.
*
* @author Gunnar Morling
*/
public class Strings {
private Strings() {
@ -26,4 +31,22 @@ public class Strings {
public static String capitalize(String name) {
return name == null ? null : name.substring( 0, 1 ).toUpperCase() + name.substring( 1 );
}
public static String join(Iterable<?> iterable, String separator) {
StringBuilder sb = new StringBuilder();
boolean isFirst = true;
for ( Object object : iterable ) {
if ( !isFirst ) {
sb.append( separator );
}
else {
isFirst = false;
}
sb.append( object );
}
return sb.toString();
}
}

View File

@ -45,6 +45,10 @@ public class ErroneousMappingsTest extends MapperTestBase {
kind = Kind.ERROR,
line = 27,
messageRegExp = ".*Unknown property \"bar\" in return type.*"),
@Diagnostic(type = ErroneousMapper.class,
kind = Kind.WARNING,
line = 28,
messageRegExp = "Unmapped target property: \"foo\""),
@Diagnostic(type = ErroneousMapper.class,
kind = Kind.ERROR,
line = 30,

View File

@ -0,0 +1,42 @@
/**
* Copyright 2012-2013 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.unmappedtarget;
public class Source {
private Long foo;
private String qux;
public Long getFoo() {
return foo;
}
public void setFoo(Long foo) {
this.foo = foo;
}
public String getQux() {
return qux;
}
public void setQux(String qux) {
this.qux = qux;
}
}

View File

@ -0,0 +1,32 @@
/**
* Copyright 2012-2013 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.unmappedtarget;
import org.mapstruct.Mapper;
import org.mapstruct.Mappers;
@Mapper
public interface SourceTargetMapper {
SourceTargetMapper INSTANCE = Mappers.getMapper( SourceTargetMapper.class );
Target sourceToTarget(Source source);
Source targetToSource(Target target);
}

View File

@ -0,0 +1,33 @@
/**
* Copyright 2012-2013 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.unmappedtarget;
import org.mapstruct.Mapper;
import org.mapstruct.Mappers;
import org.mapstruct.ReportingPolicy;
@Mapper(unmappedTargetPolicy = ReportingPolicy.ERROR)
public interface StrictSourceTargetMapper {
StrictSourceTargetMapper INSTANCE = Mappers.getMapper( StrictSourceTargetMapper.class );
Target sourceToTarget(Source source);
Source targetToSource(Target target);
}

View File

@ -0,0 +1,41 @@
/**
* Copyright 2012-2013 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.unmappedtarget;
public class Target {
private Long foo;
private int bar;
public Long getFoo() {
return foo;
}
public void setFoo(Long foo) {
this.foo = foo;
}
public int getBar() {
return bar;
}
public void setBar(int bar) {
this.bar = bar;
}
}

View File

@ -0,0 +1,84 @@
/**
* Copyright 2012-2013 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.unmappedtarget;
import javax.tools.Diagnostic.Kind;
import org.mapstruct.ap.testutil.IssueKey;
import org.mapstruct.ap.testutil.MapperTestBase;
import org.mapstruct.ap.testutil.WithClasses;
import org.mapstruct.ap.testutil.compilation.annotation.CompilationResult;
import org.mapstruct.ap.testutil.compilation.annotation.Diagnostic;
import org.mapstruct.ap.testutil.compilation.annotation.ExpectedCompilationOutcome;
import org.testng.annotations.Test;
import static org.fest.assertions.Assertions.assertThat;
/**
* Tests expected diagnostics for unmapped target properties.
*
* @author Gunnar Morling
*/
@IssueKey("35")
public class UnmappedTargetTest extends MapperTestBase {
@Test
@WithClasses({ Source.class, Target.class, SourceTargetMapper.class })
@ExpectedCompilationOutcome(
value = CompilationResult.SUCCEEDED,
diagnostics = {
@Diagnostic(type = SourceTargetMapper.class,
kind = Kind.WARNING,
line = 29,
messageRegExp = "Unmapped target property: \"bar\""),
@Diagnostic(type = SourceTargetMapper.class,
kind = Kind.WARNING,
line = 31,
messageRegExp = "Unmapped target property: \"qux\"")
}
)
public void shouldLeaveUnmappedTargetPropertyUnset() {
Source source = new Source();
source.setFoo( 42L );
Target target = SourceTargetMapper.INSTANCE.sourceToTarget( source );
assertThat( target ).isNotNull();
assertThat( target.getFoo() ).isEqualTo( 42L );
assertThat( target.getBar() ).isEqualTo( 0 );
}
@Test
@WithClasses({ Source.class, Target.class, StrictSourceTargetMapper.class })
@ExpectedCompilationOutcome(
value = CompilationResult.FAILED,
diagnostics = {
@Diagnostic(type = StrictSourceTargetMapper.class,
kind = Kind.ERROR,
line = 30,
messageRegExp = "Unmapped target property: \"bar\""),
@Diagnostic(type = StrictSourceTargetMapper.class,
kind = Kind.ERROR,
line = 32,
messageRegExp = "Unmapped target property: \"qux\"")
}
)
public void shouldRaiseErrorDueToUnsetTargetProperty() {
}
}