mirror of
https://github.com/mapstruct/mapstruct.git
synced 2025-07-12 00:00:08 +08:00
#1401 improvements by direct assigning constants
This commit is contained in:
parent
2fe7f6be2b
commit
35f5400e00
@ -1918,7 +1918,8 @@ This chapter describes several advanced options which allow to fine-tune the beh
|
||||
[[default-values-and-constants]]
|
||||
=== Default values and constants
|
||||
|
||||
Default values can be specified to set a predefined value to a target property if the corresponding source property is `null`. Constants can be specified to set such a predefined value in any case. Default values and constants are specified as String values and are subject to type conversion either via built-in conversions or the invocation of other mapping methods in order to match the type required by the target property.
|
||||
Default values can be specified to set a predefined value to a target property if the corresponding source property is `null`. Constants can be specified to set such a predefined value in any case. Default values and constants are specified as String values. When the target type is a primitive or a boxed type, the String value is taken literal. Bit / octal / decimal / hex patterns are allowed in such case as long as they are a valid literal.
|
||||
In all other cases, constant or default values are subject to type conversion either via built-in conversions or the invocation of other mapping methods in order to match the type required by the target property.
|
||||
|
||||
A mapping with a constant must not include a reference to a source property. The following example shows some mappings using default values and constants:
|
||||
|
||||
|
@ -496,13 +496,14 @@ public class BeanMappingMethod extends NormalTypeMappingMethod {
|
||||
propertyMapping = new ConstantMappingBuilder()
|
||||
.mappingContext( ctx )
|
||||
.sourceMethod( method )
|
||||
.constantExpression( "\"" + mapping.getConstant() + "\"" )
|
||||
.constantExpression( mapping.getConstant() )
|
||||
.targetProperty( targetProperty )
|
||||
.targetPropertyName( mapping.getTargetName() )
|
||||
.formattingParameters( mapping.getFormattingParameters() )
|
||||
.selectionParameters( mapping.getSelectionParameters() )
|
||||
.existingVariableNames( existingVariableNames )
|
||||
.dependsOn( mapping.getDependsOn() )
|
||||
.mirror( mapping.getMirror() )
|
||||
.build();
|
||||
handledTargets.add( mapping.getTargetName() );
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.lang.model.element.AnnotationMirror;
|
||||
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.type.DeclaredType;
|
||||
@ -116,6 +117,7 @@ public class PropertyMapping extends ModelElement {
|
||||
|
||||
protected List<String> dependsOn;
|
||||
protected Set<String> existingVariableNames;
|
||||
protected AnnotationMirror mirror;
|
||||
|
||||
MappingBuilderBase(Class<T> selfType) {
|
||||
super( selfType );
|
||||
@ -146,6 +148,11 @@ public class PropertyMapping extends ModelElement {
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
T mirror(AnnotationMirror mirror) {
|
||||
this.mirror = mirror;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
private Type determineTargetType() {
|
||||
// This is a bean mapping method, so we know the result is a declared type
|
||||
DeclaredType resultType = (DeclaredType) method.getResultType().getEffectiveType().getTypeMirror();
|
||||
@ -359,7 +366,7 @@ public class PropertyMapping extends ModelElement {
|
||||
&& ( !rhs.getSourceType().isPrimitive() || rhs.getSourcePresenceCheckerReference() != null) ) {
|
||||
// cannot check on null source if source is primitive unless it has a presence checker
|
||||
PropertyMapping build = new ConstantMappingBuilder()
|
||||
.constantExpression( '"' + defaultValue + '"' )
|
||||
.constantExpression( defaultValue )
|
||||
.formattingParameters( formattingParameters )
|
||||
.selectionParameters( selectionParameters )
|
||||
.dependsOn( dependsOn )
|
||||
@ -749,7 +756,12 @@ public class PropertyMapping extends ModelElement {
|
||||
public PropertyMapping build() {
|
||||
// source
|
||||
String sourceErrorMessagePart = "constant '" + constantExpression + "'";
|
||||
Type sourceType = ctx.getTypeFactory().getType( String.class );
|
||||
|
||||
Type sourceType = ctx.getTypeFactory().getTypeForConstant( targetType, constantExpression );
|
||||
if ( String.class.getCanonicalName().equals( sourceType.getFullyQualifiedName() ) ) {
|
||||
// convert to string
|
||||
constantExpression = "\"" + constantExpression + "\"";
|
||||
}
|
||||
|
||||
Assignment assignment = null;
|
||||
if ( !targetType.isEnumType() ) {
|
||||
@ -808,6 +820,7 @@ public class PropertyMapping extends ModelElement {
|
||||
else {
|
||||
ctx.getMessager().printMessage(
|
||||
method.getExecutable(),
|
||||
mirror,
|
||||
Message.CONSTANTMAPPING_MAPPING_NOT_FOUND,
|
||||
sourceType,
|
||||
constantExpression,
|
||||
|
@ -89,6 +89,8 @@ public class Type extends ModelElement implements Comparable<Type> {
|
||||
private final boolean isImported;
|
||||
private final boolean isVoid;
|
||||
private final boolean isStream;
|
||||
private final boolean isBoxed;
|
||||
private final boolean isOriginatedFromConstant;
|
||||
|
||||
private final List<String> enumConstants;
|
||||
|
||||
@ -111,7 +113,8 @@ public class Type extends ModelElement implements Comparable<Type> {
|
||||
BuilderInfo builderInfo,
|
||||
String packageName, String name, String qualifiedName,
|
||||
boolean isInterface, boolean isEnumType, boolean isIterableType,
|
||||
boolean isCollectionType, boolean isMapType, boolean isStreamType, boolean isImported) {
|
||||
boolean isCollectionType, boolean isMapType, boolean isStreamType, boolean isImported,
|
||||
boolean isBoxed, boolean isOriginatedFromConstant ) {
|
||||
|
||||
this.typeUtils = typeUtils;
|
||||
this.elementUtils = elementUtils;
|
||||
@ -135,6 +138,8 @@ public class Type extends ModelElement implements Comparable<Type> {
|
||||
this.isStream = isStreamType;
|
||||
this.isImported = isImported;
|
||||
this.isVoid = typeMirror.getKind() == TypeKind.VOID;
|
||||
this.isBoxed = isBoxed;
|
||||
this.isOriginatedFromConstant = isOriginatedFromConstant;
|
||||
|
||||
if ( isEnumType ) {
|
||||
enumConstants = new ArrayList<String>();
|
||||
@ -384,7 +389,9 @@ public class Type extends ModelElement implements Comparable<Type> {
|
||||
isCollectionType,
|
||||
isMapType,
|
||||
isStream,
|
||||
isImported
|
||||
isImported,
|
||||
isBoxed,
|
||||
isOriginatedFromConstant
|
||||
);
|
||||
}
|
||||
|
||||
@ -913,4 +920,13 @@ public class Type extends ModelElement implements Comparable<Type> {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isBoxed() {
|
||||
return isBoxed;
|
||||
}
|
||||
|
||||
public boolean hasOriginatedFromConstant() {
|
||||
return isOriginatedFromConstant;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -64,6 +64,7 @@ import org.mapstruct.ap.spi.BuilderInfo;
|
||||
import org.mapstruct.ap.spi.BuilderProvider;
|
||||
import org.mapstruct.ap.spi.DefaultBuilderProvider;
|
||||
import org.mapstruct.ap.spi.TypeHierarchyErroneousException;
|
||||
import org.mapstruct.ap.internal.util.NativeTypes;
|
||||
|
||||
import static org.mapstruct.ap.internal.model.common.ImplementationType.withDefaultConstructor;
|
||||
import static org.mapstruct.ap.internal.model.common.ImplementationType.withInitialCapacity;
|
||||
@ -131,6 +132,10 @@ public class TypeFactory {
|
||||
}
|
||||
|
||||
public Type getType(String canonicalName) {
|
||||
return getType( canonicalName, false );
|
||||
}
|
||||
|
||||
private Type getType(String canonicalName, boolean isOriginatedFromConstant) {
|
||||
TypeElement typeElement = elementUtils.getTypeElement( canonicalName );
|
||||
|
||||
if ( typeElement == null ) {
|
||||
@ -139,7 +144,31 @@ public class TypeFactory {
|
||||
);
|
||||
}
|
||||
|
||||
return getType( typeElement );
|
||||
return getType( typeElement, isOriginatedFromConstant );
|
||||
}
|
||||
|
||||
public Type getTypeForConstant(Type targetType, String literal) {
|
||||
Type result = null;
|
||||
if ( targetType.isPrimitive() ) {
|
||||
TypeKind kind = targetType.getTypeMirror().getKind();
|
||||
boolean assignable = NativeTypes.isStringAssignable( kind, true, literal );
|
||||
if ( assignable ) {
|
||||
result = getType( targetType.getTypeMirror(), true );
|
||||
}
|
||||
}
|
||||
else {
|
||||
TypeKind boxedTypeKind = NativeTypes.getWrapperKind( targetType.getFullyQualifiedName() );
|
||||
if ( boxedTypeKind != null ) {
|
||||
boolean assignable = NativeTypes.isStringAssignable( boxedTypeKind, false, literal );
|
||||
if ( assignable ) {
|
||||
result = getType( targetType.getTypeMirror(), true );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( result == null ) {
|
||||
result = getType( String.class.getCanonicalName(), true );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -165,7 +194,15 @@ public class TypeFactory {
|
||||
return getType( typeElement.asType() );
|
||||
}
|
||||
|
||||
private Type getType(TypeElement typeElement, boolean originatedFromConstant) {
|
||||
return getType( typeElement.asType(), originatedFromConstant );
|
||||
}
|
||||
|
||||
public Type getType(TypeMirror mirror) {
|
||||
return getType( mirror, false );
|
||||
}
|
||||
|
||||
private Type getType(TypeMirror mirror, boolean originatedFromConstant) {
|
||||
if ( !canBeProcessed( mirror ) ) {
|
||||
throw new TypeHierarchyErroneousException( mirror );
|
||||
}
|
||||
@ -186,6 +223,7 @@ public class TypeFactory {
|
||||
TypeElement typeElement;
|
||||
Type componentType;
|
||||
boolean isImported;
|
||||
boolean isBoxed = false;
|
||||
|
||||
if ( mirror.getKind() == TypeKind.DECLARED ) {
|
||||
DeclaredType declaredType = (DeclaredType) mirror;
|
||||
@ -207,6 +245,7 @@ public class TypeFactory {
|
||||
|
||||
componentType = null;
|
||||
isImported = isImported( name, qualifiedName );
|
||||
isBoxed = NativeTypes.isWrapped( qualifiedName );
|
||||
}
|
||||
else if ( mirror.getKind() == TypeKind.ARRAY ) {
|
||||
TypeMirror componentTypeMirror = getComponentType( mirror );
|
||||
@ -267,7 +306,9 @@ public class TypeFactory {
|
||||
isCollectionType,
|
||||
isMapType,
|
||||
isStreamType,
|
||||
isImported
|
||||
isImported,
|
||||
isBoxed,
|
||||
originatedFromConstant
|
||||
);
|
||||
}
|
||||
|
||||
@ -315,8 +356,8 @@ public class TypeFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Type for given method as part of usedMapper. Possibly parameterized types in method declaration
|
||||
* will be evaluated to concrete types then.
|
||||
* Get the Type for given method as part of usedMapper. Possibly parameterized types in method declaration will be
|
||||
* evaluated to concrete types then.
|
||||
*
|
||||
* @param includingType the type on which's scope the method type shall be evaluated
|
||||
* @param method the method
|
||||
@ -479,7 +520,9 @@ public class TypeFactory {
|
||||
implementationType.isCollectionType(),
|
||||
implementationType.isMapType(),
|
||||
implementationType.isStreamType(),
|
||||
isImported( implementationType.getName(), implementationType.getFullyQualifiedName() )
|
||||
isImported( implementationType.getName(), implementationType.getFullyQualifiedName() ),
|
||||
implementationType.isBoxed(),
|
||||
implementationType.hasOriginatedFromConstant()
|
||||
);
|
||||
return implementation.createNew( replacement );
|
||||
}
|
||||
|
@ -253,6 +253,18 @@ public class MappingResolverImpl implements MappingResolver {
|
||||
return simpleAssignment;
|
||||
}
|
||||
|
||||
// At this point the SourceType will either
|
||||
// 1. be a String
|
||||
// 2. or when its a primitive / wrapped type and analysis successful equal to its TargetType. But in that
|
||||
// case it should have been direct assignable.
|
||||
// In case of 1. and the target type is still a wrapped or primitive type we must assume that the check
|
||||
// in NativeType is not successful. We don't want to go through type conversion, double mappings etc.
|
||||
// with something that we already know to be wrong.
|
||||
if ( sourceType.hasOriginatedFromConstant() && ( targetType.isPrimitive() || targetType.isBoxed() ) ) {
|
||||
// TODO: convey some error message
|
||||
return null;
|
||||
}
|
||||
|
||||
// then type conversion
|
||||
Assignment conversion = resolveViaConversion( sourceType, targetType );
|
||||
if ( conversion != null ) {
|
||||
|
@ -25,6 +25,8 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.lang.model.type.TypeKind;
|
||||
|
||||
/**
|
||||
* Provides functionality around the Java primitive data types and their wrapper
|
||||
@ -37,6 +39,195 @@ public class NativeTypes {
|
||||
private static final Map<Class<?>, Class<?>> WRAPPER_TO_PRIMITIVE_TYPES;
|
||||
private static final Map<Class<?>, Class<?>> PRIMITIVE_TO_WRAPPER_TYPES;
|
||||
private static final Set<Class<?>> NUMBER_TYPES = new HashSet<Class<?>>();
|
||||
private static final Map<String, TypeKind> WRAPPER_NAME_TO_PRIMITIVE_TYPES;
|
||||
|
||||
private static final Pattern PTRN_HEX = Pattern.compile( "^0[x|X].*" );
|
||||
private static final Pattern PTRN_OCT = Pattern.compile( "^0_*[0-7].*" );
|
||||
private static final Pattern PTRN_BIN = Pattern.compile( "^0[b|B].*" );
|
||||
private static final Pattern PTRN_FLOAT_DEC_ZERO = Pattern.compile( "^[^eE]*[1-9].*[eE]?.*" );
|
||||
private static final Pattern PTRN_FLOAT_HEX_ZERO = Pattern.compile( "^[^pP]*[1-9a-fA-F].*[pP]?.*" );
|
||||
|
||||
private static final Pattern PTRN_SIGN = Pattern.compile( "^[\\+|-]" );
|
||||
|
||||
private static final Pattern PTRN_LONG = Pattern.compile( "[l|L]$" );
|
||||
private static final Pattern PTRN_FLOAT = Pattern.compile( "[f|F]$" );
|
||||
private static final Pattern PTRN_DOUBLE = Pattern.compile( "[d|D]$" );
|
||||
|
||||
private static final Pattern PTRN_FAULTY_UNDERSCORE_INT = Pattern.compile( "^_|_$|-_|_-|\\+_|_\\+" );
|
||||
private static final Pattern PTRN_FAULTY_UNDERSCORE_FLOAT = Pattern.compile( "^_|_$|-_|_-|\\+_|_\\+|\\._|_\\." );
|
||||
private static final Pattern PTRN_FAULTY_DEC_UNDERSCORE_FLOAT = Pattern.compile( "_e|_E|e_|E_" );
|
||||
private static final Pattern PTRN_FAULTY_HEX_UNDERSCORE_FLOAT = Pattern.compile( "_p|_P|p_|P_" );
|
||||
|
||||
private static final Map<TypeKind, NumberFormatValidator> VALIDATORS = initValidators();
|
||||
|
||||
private interface NumberFormatValidator {
|
||||
|
||||
boolean validate(boolean isPrimitive, String s);
|
||||
}
|
||||
|
||||
private abstract static class NumberRepresentation {
|
||||
|
||||
int radix;
|
||||
String val;
|
||||
boolean isIntegralType;
|
||||
boolean isLong;
|
||||
boolean isFloat;
|
||||
boolean isPrimitive;
|
||||
|
||||
NumberRepresentation(String in, boolean isIntegralType, boolean isLong, boolean isFloat, boolean isPrimitive) {
|
||||
this.isLong = isLong;
|
||||
this.isFloat = isFloat;
|
||||
this.isIntegralType = isIntegralType;
|
||||
this.isPrimitive = isPrimitive;
|
||||
|
||||
String valWithoutSign;
|
||||
boolean isNegative = in.startsWith( "-" );
|
||||
boolean hasSign = PTRN_SIGN.matcher( in ).find();
|
||||
if ( hasSign ) {
|
||||
valWithoutSign = in.substring( 1 );
|
||||
}
|
||||
else {
|
||||
valWithoutSign = in;
|
||||
}
|
||||
if ( PTRN_HEX.matcher( valWithoutSign ).matches() ) {
|
||||
// hex
|
||||
radix = 16;
|
||||
val = (isNegative ? "-" : "") + valWithoutSign.substring( 2 );
|
||||
}
|
||||
else if ( PTRN_BIN.matcher( valWithoutSign ).matches() ) {
|
||||
// binary
|
||||
radix = 2;
|
||||
val = (isNegative ? "-" : "") + valWithoutSign.substring( 2 );
|
||||
}
|
||||
else if ( PTRN_OCT.matcher( valWithoutSign ).matches() ) {
|
||||
// octal
|
||||
radix = 8;
|
||||
val = (isNegative ? "-" : "") + valWithoutSign.substring( 1 );
|
||||
}
|
||||
else {
|
||||
// decimal
|
||||
radix = 10;
|
||||
val = (isNegative ? "-" : "") + valWithoutSign;
|
||||
}
|
||||
}
|
||||
|
||||
abstract boolean parse(String val, int radix);
|
||||
|
||||
boolean validate() {
|
||||
try {
|
||||
strip();
|
||||
return parse( val, radix );
|
||||
}
|
||||
catch ( NumberFormatException ex ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void strip() {
|
||||
if ( isIntegralType ) {
|
||||
removeAndValidateIntegerLiteralSuffix();
|
||||
removeAndValidateIntegerLiteralUnderscore();
|
||||
}
|
||||
else {
|
||||
removeAndValidateFloatingPointLiteralSuffix();
|
||||
removeAndValidateFloatingPointLiteralUnderscore();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* remove java7+ underscores from the input
|
||||
*/
|
||||
void removeAndValidateIntegerLiteralUnderscore() {
|
||||
if ( PTRN_FAULTY_UNDERSCORE_INT.matcher( val ).find() ) {
|
||||
throw new NumberFormatException("Improperly placed underscores");
|
||||
}
|
||||
else {
|
||||
val = val.replace( "_", "" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* remove java7+ underscores from the input
|
||||
*/
|
||||
void removeAndValidateFloatingPointLiteralUnderscore() {
|
||||
boolean isHex = radix == 16;
|
||||
if ( PTRN_FAULTY_UNDERSCORE_FLOAT.matcher( val ).find()
|
||||
|| !isHex && PTRN_FAULTY_DEC_UNDERSCORE_FLOAT.matcher( val ).find()
|
||||
|| isHex && PTRN_FAULTY_HEX_UNDERSCORE_FLOAT.matcher( val ).find() ) {
|
||||
throw new NumberFormatException("Improperly placed underscores");
|
||||
}
|
||||
else {
|
||||
val = val.replace( "_", "" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void removeAndValidateIntegerLiteralSuffix() {
|
||||
boolean endsWithLSuffix = PTRN_LONG.matcher( val ).find();
|
||||
// error handling
|
||||
if (endsWithLSuffix && !isLong) {
|
||||
throw new NumberFormatException("L/l not allowed for non-long types");
|
||||
}
|
||||
if (!isPrimitive && !endsWithLSuffix && isLong) {
|
||||
throw new NumberFormatException("L/l mandatory for boxed long");
|
||||
}
|
||||
// remove suffix
|
||||
if ( endsWithLSuffix ) {
|
||||
val = val.substring( 0, val.length() - 1 );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Double suffix forbidden for float.
|
||||
*
|
||||
* @param isFloat
|
||||
*/
|
||||
void removeAndValidateFloatingPointLiteralSuffix() {
|
||||
boolean endsWithLSuffix = PTRN_LONG.matcher( val ).find();
|
||||
boolean endsWithFSuffix = PTRN_FLOAT.matcher( val ).find();
|
||||
boolean endsWithDSuffix = PTRN_DOUBLE.matcher( val ).find();
|
||||
// error handling
|
||||
if ( isFloat && endsWithDSuffix ) {
|
||||
throw new NumberFormatException("Assiging double to a float");
|
||||
}
|
||||
// remove suffix
|
||||
if ( endsWithLSuffix || endsWithFSuffix || endsWithDSuffix ) {
|
||||
val = val.substring( 0, val.length() - 1 );
|
||||
}
|
||||
}
|
||||
|
||||
boolean floatHasBecomeZero(float parsed) {
|
||||
if ( parsed == 0f ) {
|
||||
return floatHasBecomeZero();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
boolean doubleHasBecomeZero(double parsed) {
|
||||
if ( parsed == 0d ) {
|
||||
return floatHasBecomeZero();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean floatHasBecomeZero() {
|
||||
if ( radix == 10 ) {
|
||||
// decimal, should be at least some number before exponent (eE) unequal to 0.
|
||||
return PTRN_FLOAT_DEC_ZERO.matcher( val ).matches();
|
||||
}
|
||||
else {
|
||||
// hex, should be at least some number before exponent (pP) unequal to 0.
|
||||
return PTRN_FLOAT_HEX_ZERO.matcher( val ).matches();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private NativeTypes() {
|
||||
}
|
||||
@ -80,6 +271,19 @@ public class NativeTypes {
|
||||
NUMBER_TYPES.add( Double.class );
|
||||
NUMBER_TYPES.add( BigInteger.class );
|
||||
NUMBER_TYPES.add( BigDecimal.class );
|
||||
|
||||
Map<String, TypeKind> tmp2 = new HashMap<String, TypeKind>();
|
||||
tmp2.put( Boolean.class.getName(), TypeKind.BOOLEAN );
|
||||
tmp2.put( Byte.class.getName(), TypeKind.BYTE );
|
||||
tmp2.put( Character.class.getName(), TypeKind.CHAR );
|
||||
tmp2.put( Double.class.getName(), TypeKind.DOUBLE );
|
||||
tmp2.put( Float.class.getName(), TypeKind.FLOAT );
|
||||
tmp2.put( Integer.class.getName(), TypeKind.INT );
|
||||
tmp2.put( Long.class.getName(), TypeKind.LONG );
|
||||
tmp2.put( Short.class.getName(), TypeKind.SHORT );
|
||||
|
||||
WRAPPER_NAME_TO_PRIMITIVE_TYPES = Collections.unmodifiableMap( tmp2 );
|
||||
|
||||
}
|
||||
|
||||
public static Class<?> getWrapperType(Class<?> clazz) {
|
||||
@ -98,6 +302,14 @@ public class NativeTypes {
|
||||
return WRAPPER_TO_PRIMITIVE_TYPES.get( clazz );
|
||||
}
|
||||
|
||||
public static boolean isWrapped(String fullyQualifiedName) {
|
||||
return WRAPPER_NAME_TO_PRIMITIVE_TYPES.containsKey( fullyQualifiedName );
|
||||
}
|
||||
|
||||
public static TypeKind getWrapperKind(String fullyQualifiedName) {
|
||||
return WRAPPER_NAME_TO_PRIMITIVE_TYPES.get( fullyQualifiedName );
|
||||
}
|
||||
|
||||
public static boolean isNumber(Class<?> clazz) {
|
||||
if ( clazz == null ) {
|
||||
return false;
|
||||
@ -106,4 +318,125 @@ public class NativeTypes {
|
||||
return NUMBER_TYPES.contains( clazz );
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isStringAssignable(TypeKind kind, boolean isPrimitive, String in) {
|
||||
NumberFormatValidator validator = VALIDATORS.get( kind );
|
||||
return validator != null && validator.validate( isPrimitive, in );
|
||||
}
|
||||
|
||||
private static Map<TypeKind, NumberFormatValidator> initValidators() {
|
||||
Map<TypeKind, NumberFormatValidator> result = new HashMap<TypeKind, NumberFormatValidator>();
|
||||
result.put( TypeKind.BOOLEAN, new NumberFormatValidator() {
|
||||
@Override
|
||||
public boolean validate(boolean isPrimitive, String s) {
|
||||
return "true".equals( s ) || "false".equals( s );
|
||||
}
|
||||
} );
|
||||
result.put( TypeKind.CHAR, new NumberFormatValidator() {
|
||||
@Override
|
||||
public boolean validate(boolean isPrimitive, String s) {
|
||||
return s.length() == 3 && s.startsWith( "'" ) && s.endsWith( "'" );
|
||||
}
|
||||
} );
|
||||
result.put( TypeKind.BYTE, new NumberFormatValidator() {
|
||||
@Override
|
||||
public boolean validate(boolean isPrimitive, String s) {
|
||||
NumberRepresentation br = new NumberRepresentation( s, true, false, false, isPrimitive ) {
|
||||
|
||||
@Override
|
||||
boolean parse(String val, int radix) {
|
||||
Byte.parseByte( val, radix );
|
||||
return true;
|
||||
}
|
||||
};
|
||||
return br.validate();
|
||||
}
|
||||
} );
|
||||
result.put( TypeKind.DOUBLE, new NumberFormatValidator() {
|
||||
@Override
|
||||
public boolean validate(boolean isPrimitive, String s) {
|
||||
NumberRepresentation br = new NumberRepresentation( s, false, false, false, isPrimitive ) {
|
||||
|
||||
@Override
|
||||
boolean parse(String val, int radix) {
|
||||
Double d = Double.parseDouble( radix == 16 ? "0x" + val : val );
|
||||
return !d.isInfinite() && !doubleHasBecomeZero( d );
|
||||
}
|
||||
};
|
||||
return br.validate();
|
||||
}
|
||||
} );
|
||||
result.put( TypeKind.FLOAT, new NumberFormatValidator() {
|
||||
@Override
|
||||
public boolean validate(boolean isPrimitive, String s) {
|
||||
|
||||
NumberRepresentation br = new NumberRepresentation( s, false, false, true, isPrimitive ) {
|
||||
@Override
|
||||
boolean parse(String val, int radix) {
|
||||
Float f = Float.parseFloat( radix == 16 ? "0x" + val : val );
|
||||
return !f.isInfinite() && !floatHasBecomeZero( f );
|
||||
}
|
||||
};
|
||||
return br.validate();
|
||||
}
|
||||
} );
|
||||
result.put( TypeKind.INT, new NumberFormatValidator() {
|
||||
@Override
|
||||
public boolean validate(boolean isPrimitive, String s) {
|
||||
NumberRepresentation br = new NumberRepresentation( s, true, false, false, isPrimitive ) {
|
||||
|
||||
@Override
|
||||
boolean parse(String val, int radix) {
|
||||
if ( radix == 10 ) {
|
||||
// when decimal: treat like signed
|
||||
Integer.parseInt( val, radix );
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
// when binary, octal or hex: treat like unsigned
|
||||
return new BigInteger( val, radix ).bitLength() <= 32;
|
||||
}
|
||||
}
|
||||
};
|
||||
return br.validate();
|
||||
}
|
||||
} );
|
||||
result.put( TypeKind.LONG, new NumberFormatValidator() {
|
||||
@Override
|
||||
public boolean validate(boolean isPrimitive, String s) {
|
||||
NumberRepresentation br = new NumberRepresentation( s, true, true, false, isPrimitive ) {
|
||||
|
||||
@Override
|
||||
boolean parse(String val, int radix) {
|
||||
if ( radix == 10 ) {
|
||||
// when decimal: treat like signed
|
||||
Long.parseLong( val, radix );
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
// when binary, octal or hex: treat like unsigned
|
||||
return new BigInteger( val, radix ).bitLength() <= 64;
|
||||
}
|
||||
}
|
||||
};
|
||||
return br.validate();
|
||||
}
|
||||
} );
|
||||
result.put( TypeKind.SHORT, new NumberFormatValidator() {
|
||||
@Override
|
||||
public boolean validate(boolean isPrimitive, String s) {
|
||||
NumberRepresentation br = new NumberRepresentation( s, true, false, false, isPrimitive ) {
|
||||
|
||||
@Override
|
||||
boolean parse(String val, int radix) {
|
||||
Short.parseShort( val, radix );
|
||||
return true;
|
||||
}
|
||||
};
|
||||
return br.validate();
|
||||
}
|
||||
} );
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -183,6 +183,8 @@ public class DateFormatValidatorFactoryTest {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false );
|
||||
}
|
||||
|
||||
|
@ -134,6 +134,8 @@ public class DefaultConversionContextTest {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false );
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,342 @@
|
||||
/**
|
||||
* Copyright 2012-2017 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.source.constants;
|
||||
|
||||
import javax.lang.model.type.TypeKind;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mapstruct.ap.internal.util.NativeTypes.isStringAssignable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sjaak Derksen
|
||||
*/
|
||||
public class ConstantOptimizingTest {
|
||||
|
||||
/**
|
||||
* checkout https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
|
||||
*
|
||||
* The following example shows other ways you can use the underscore in numeric literals:
|
||||
*/
|
||||
@Test
|
||||
public void testUnderscorePlacement1() {
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "1234_5678_9012_3456L" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "999_99_9999L" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.FLOAT, true, "3.14_15F" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "0xFF_EC_DE_5EL" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "0xCAFE_BABEL" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "0x7fff_ffff_ffff_ffffL" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.BYTE, true, "0b0010_0101" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "0b11010010_01101001_10010100_10010010L" ) ).isTrue();
|
||||
}
|
||||
|
||||
/**
|
||||
* checkout https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
|
||||
*
|
||||
* You can place underscores only between digits; you cannot place underscores in the following places:
|
||||
* <ol>
|
||||
* <li>At the beginning or end of a number</li>
|
||||
* <li>Adjacent to a decimal point in a floating point literal</li>
|
||||
* <li>Prior to an F or L suffix</li>
|
||||
* <li>In positions where a string of digits is expected</li>
|
||||
* </ol>
|
||||
* The following examples demonstrate valid and invalid underscore placements (which are highlighted) in numeric
|
||||
* literals:
|
||||
*/
|
||||
@Test
|
||||
public void testUnderscorePlacement2() {
|
||||
|
||||
// Invalid: cannot put underscores
|
||||
// adjacent to a decimal point
|
||||
assertThat( isStringAssignable( TypeKind.FLOAT, true, "3_.1415F" ) ).isFalse();
|
||||
|
||||
// Invalid: cannot put underscores
|
||||
// adjacent to a decimal point
|
||||
assertThat( isStringAssignable( TypeKind.FLOAT, true, "3._1415F" ) ).isFalse();
|
||||
|
||||
// Invalid: cannot put underscores
|
||||
// prior to an L suffix
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "999_99_9999_L" ) ).isFalse();
|
||||
|
||||
// OK (decimal literal)
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "5_2" ) ).isTrue();
|
||||
|
||||
// Invalid: cannot put underscores
|
||||
// At the end of a literal
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "52_" ) ).isFalse();
|
||||
|
||||
// OK (decimal literal)
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "5_______2" ) ).isTrue();
|
||||
|
||||
// Invalid: cannot put underscores
|
||||
// in the 0x radix prefix
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "0_x52" ) ).isFalse();
|
||||
|
||||
// Invalid: cannot put underscores
|
||||
// at the beginning of a number
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "0x_52" ) ).isFalse();
|
||||
|
||||
// OK (hexadecimal literal)
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "0x5_2" ) ).isTrue();
|
||||
|
||||
// Invalid: cannot put underscores
|
||||
// at the end of a number
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "0x52_" ) ).isFalse();
|
||||
}
|
||||
|
||||
/**
|
||||
* checkout https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
|
||||
*
|
||||
* The following example shows other ways you can use the underscore in numeric literals:
|
||||
*/
|
||||
@Test
|
||||
public void testIntegerLiteralFromJLS() {
|
||||
|
||||
// largest positive int: dec / octal / int / binary
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "2147483647" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "0x7fff_ffff" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "0177_7777_7777" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "0b0111_1111_1111_1111_1111_1111_1111_1111" ) ).isTrue();
|
||||
|
||||
// most negative int: dec / octal / int / binary
|
||||
// NOTE parseInt should be changed to parseUnsignedInt in Java, than the - sign can disssapear (java8)
|
||||
// and the function will be true to what the compiler shows.
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "-2147483648" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "0x8000_0000" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "0200_0000_0000" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "0b1000_0000_0000_0000_0000_0000_0000_0000" ) ).isTrue();
|
||||
|
||||
// -1 representation int: dec / octal / int / binary
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "-1" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "0xffff_ffff" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "0377_7777_7777" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "0b1111_1111_1111_1111_1111_1111_1111_1111" ) ).isTrue();
|
||||
|
||||
// largest positive long: dec / octal / int / binary
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "9223372036854775807L" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "0x7fff_ffff_ffff_ffffL" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "07_7777_7777_7777_7777_7777L" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "0b0111_1111_1111_1111_1111_1111_1111_1111_1111_1111_"
|
||||
+ "1111_1111_1111_1111_1111_1111L" ) ).isTrue();
|
||||
// most negative long: dec / octal / int / binary
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "-9223372036854775808L" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "0x8000_0000_0000_0000L" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "010_0000_0000_0000_0000_0000L" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "0b1000_0000_0000_0000_0000_0000_0000_0000_0000_0000_0000_"
|
||||
+ "0000_0000_0000_0000_0000L" ) ).isTrue();
|
||||
// -1 representation long: dec / octal / int / binary
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "-1L" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "0xffff_ffff_ffff_ffffL" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "017_7777_7777_7777_7777_7777L" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "0b1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_1111_"
|
||||
+ "1111_1111_1111_1111_1111L" ) ).isTrue();
|
||||
|
||||
// some examples of ints
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "0" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "2" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "0372" ) ).isTrue();
|
||||
//assertThat( isStringAssignable( TypeKind.INT, true, "0xDada_Cafe" ) ).isTrue(); java8
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "1996" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "0x00_FF__00_FF" ) ).isTrue();
|
||||
|
||||
// some examples of longs
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "0777l" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "0x100000000L" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "2_147_483_648L" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "0xC0B0L" ) ).isTrue();
|
||||
}
|
||||
|
||||
/**
|
||||
* checkout https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
|
||||
*
|
||||
* The following example shows other ways you can use the underscore in numeric literals:
|
||||
*/
|
||||
@Test
|
||||
public void testFloatingPoingLiteralFromJLS() {
|
||||
|
||||
// The largest positive finite literal of type float is 3.4028235e38f.
|
||||
assertThat( isStringAssignable( TypeKind.FLOAT, true, "3.4028235e38f" ) ).isTrue();
|
||||
// The smallest positive finite non-zero literal of type float is 1.40e-45f.
|
||||
assertThat( isStringAssignable( TypeKind.FLOAT, true, "1.40e-45f" ) ).isTrue();
|
||||
// The largest positive finite literal of type double is 1.7976931348623157e308.
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "1.7976931348623157e308" ) ).isTrue();
|
||||
// The smallest positive finite non-zero literal of type double is 4.9e-324
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4.9e-324" ) ).isTrue();
|
||||
|
||||
// some floats
|
||||
assertThat( isStringAssignable( TypeKind.FLOAT, true, "3.1e1F" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.FLOAT, true, "2.f" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.FLOAT, true, ".3f" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.FLOAT, true, "0f" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.FLOAT, true, "3.14f" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.FLOAT, true, "6.022137e+23f" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.FLOAT, true, "-3.14f" ) ).isTrue();
|
||||
|
||||
// some doubles
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "1e1" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "1e+1" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "2." ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, ".3" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "0.0" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "3.14" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "-3.14" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "1e-9D" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "1e137" ) ).isTrue();
|
||||
|
||||
// too large (infinitve)
|
||||
assertThat( isStringAssignable( TypeKind.FLOAT, true, "3.4028235e38f" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "1.7976931348623157e308" ) ).isTrue();
|
||||
|
||||
// too large (infinitve)
|
||||
assertThat( isStringAssignable( TypeKind.FLOAT, true, "3.4028235e39f" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "1.7976931348623159e308" ) ).isFalse();
|
||||
|
||||
// small
|
||||
assertThat( isStringAssignable( TypeKind.FLOAT, true, "1.40e-45f" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.FLOAT, true, "0x1.0p-149" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4.9e-324" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "0x0.001P-1062d" ) ).isTrue();
|
||||
|
||||
// too small
|
||||
assertThat( isStringAssignable( TypeKind.FLOAT, true, "1.40e-46f" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.FLOAT, true, "0x1.0p-150" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4.9e-325" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "0x0.001p-1063d" ) ).isFalse();
|
||||
}
|
||||
|
||||
/**
|
||||
* checkout https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
|
||||
*
|
||||
* The following example shows other ways you can use the underscore in numeric literals:
|
||||
*/
|
||||
@Test
|
||||
public void testBooleanLiteralFromJLS() {
|
||||
assertThat( isStringAssignable( TypeKind.BOOLEAN, true, "true" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.BOOLEAN, true, "false" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.BOOLEAN, true, "FALSE" ) ).isFalse();
|
||||
}
|
||||
|
||||
/**
|
||||
* checkout https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
|
||||
*
|
||||
* The following example shows other ways you can use the underscore in numeric literals:
|
||||
*/
|
||||
@Test
|
||||
public void testCharLiteralFromJLS() {
|
||||
|
||||
assertThat( isStringAssignable( TypeKind.CHAR, true, "'a'" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.CHAR, true, "'%'" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.CHAR, true, "'\t'" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.CHAR, true, "'\\'" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.CHAR, true, "'\''" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.CHAR, true, "'\u03a9'" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.CHAR, true, "'\uFFFF'" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.CHAR, true, "'\177'" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.CHAR, true, "'Ω'" ) ).isTrue();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShortAndByte() {
|
||||
assertThat( isStringAssignable( TypeKind.SHORT, true, "0xFE" ) ).isTrue();
|
||||
|
||||
// some examples of ints
|
||||
assertThat( isStringAssignable( TypeKind.BYTE, true, "0" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.BYTE, true, "2" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.BYTE, true, "127" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.BYTE, true, "-128" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.SHORT, true, "1996" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.SHORT, true, "-1996" ) ).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMiscellaneousErroneousPatterns() {
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "1F" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.FLOAT, true, "1D" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "_1" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "1_" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "0x_1" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "0_x1" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4.9e_-3" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4.9_e-3" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4._9e-3" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4_.9e-3" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "_4.9e-3" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4.9E-3_" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4.9E_-3" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4.9E-_3" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4.9E+-3" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4.9E+_3" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "4.9_E-3" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "0x0.001_P-10d" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "0x0.001P_-10d" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "0x0.001_p-10d" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.DOUBLE, true, "0x0.001p_-10d" ) ).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNegatives() {
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "-0xffaa" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "-0377_7777" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "-0b1111_1111" ) ).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFaultyChar() {
|
||||
assertThat( isStringAssignable( TypeKind.CHAR, true, "''" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.CHAR, true, "'a" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.CHAR, true, "'aa" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.CHAR, true, "a'" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.CHAR, true, "aa'" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.CHAR, true, "'" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.CHAR, true, "a" ) ).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFloatWithLongLiteral() {
|
||||
assertThat( isStringAssignable( TypeKind.FLOAT, true, "156L" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.FLOAT, true, "156l" ) ).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongPrimitivesAndNonRequiredLongSuffix() {
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "156" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "156l" ) ).isTrue();
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "156L" ) ).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntPrimitiveWithLongSuffix() {
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "156l" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "156L" ) ).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTooBigIntegersAndBigLongs() {
|
||||
assertThat( isStringAssignable( TypeKind.INT, true, "0xFFFF_FFFF_FFFF" ) ).isFalse();
|
||||
assertThat( isStringAssignable( TypeKind.LONG, true, "0xFFFF_FFFF_FFFF_FFFF_FFFF" ) ).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonSupportedPrimitiveType() {
|
||||
assertThat( isStringAssignable( TypeKind.VOID, true, "0xFFFF_FFFF_FFFF" ) ).isFalse();
|
||||
}
|
||||
|
||||
}
|
@ -35,7 +35,7 @@ public interface ErroneousMapper1 {
|
||||
@Mapping(target = "stringConstant", constant = "stringConstant"),
|
||||
@Mapping(target = "emptyStringConstant", constant = ""),
|
||||
@Mapping(source = "test", target = "integerConstant", constant = "14"),
|
||||
@Mapping(target = "longWrapperConstant", constant = "3001"),
|
||||
@Mapping(target = "longWrapperConstant", constant = "3001L"),
|
||||
@Mapping(target = "dateConstant", dateFormat = "dd-MM-yyyy", constant = "09-01-2014"),
|
||||
@Mapping(target = "nameConstants", constant = "jack-jill-tom"),
|
||||
@Mapping(target = "country", constant = "THE_NETHERLANDS")
|
||||
|
@ -35,7 +35,7 @@ public interface ErroneousMapper3 {
|
||||
@Mapping(target = "stringConstant", constant = "stringConstant"),
|
||||
@Mapping(target = "emptyStringConstant", constant = ""),
|
||||
@Mapping(target = "integerConstant", expression = "java('test')", constant = "14"),
|
||||
@Mapping(target = "longWrapperConstant", constant = "3001"),
|
||||
@Mapping(target = "longWrapperConstant", constant = "3001L"),
|
||||
@Mapping(target = "dateConstant", dateFormat = "dd-MM-yyyy", constant = "09-01-2014"),
|
||||
@Mapping(target = "nameConstants", constant = "jack-jill-tom"),
|
||||
@Mapping(target = "country", constant = "THE_NETHERLANDS")
|
||||
|
@ -35,7 +35,7 @@ public interface ErroneousMapper4 {
|
||||
@Mapping(target = "stringConstant", constant = "stringConstant"),
|
||||
@Mapping(target = "emptyStringConstant", constant = ""),
|
||||
@Mapping(source = "test", target = "integerConstant", expression = "java('test')"),
|
||||
@Mapping(target = "longWrapperConstant", constant = "3001"),
|
||||
@Mapping(target = "longWrapperConstant", constant = "3001L"),
|
||||
@Mapping(target = "dateConstant", dateFormat = "dd-MM-yyyy", constant = "09-01-2014"),
|
||||
@Mapping(target = "nameConstants", constant = "jack-jill-tom"),
|
||||
@Mapping(target = "country", constant = "THE_NETHERLANDS")
|
||||
|
@ -35,7 +35,7 @@ public interface ErroneousMapper5 {
|
||||
@Mapping(target = "stringConstant", constant = "stringConstant"),
|
||||
@Mapping(target = "emptyStringConstant", constant = ""),
|
||||
@Mapping(target = "integerConstant", constant = "14"),
|
||||
@Mapping(target = "longWrapperConstant", constant = "3001"),
|
||||
@Mapping(target = "longWrapperConstant", constant = "3001L"),
|
||||
@Mapping(target = "dateConstant", dateFormat = "dd-MM-yyyy", constant = "09-01-2014"),
|
||||
@Mapping(target = "nameConstants", constant = "jack-jill-tom"),
|
||||
@Mapping(target = "country", constant = "DENMARK")
|
||||
|
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright 2012-2017 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.source.constants;
|
||||
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.Mappings;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
/**
|
||||
* @author Sjaak Derksen
|
||||
*/
|
||||
@Mapper(uses = StringListMapper.class)
|
||||
public interface ErroneousMapper6 {
|
||||
|
||||
ErroneousMapper6 INSTANCE = Mappers.getMapper( ErroneousMapper6.class );
|
||||
|
||||
@Mappings({
|
||||
@Mapping(target = "stringConstant", constant = "stringConstant"),
|
||||
@Mapping(target = "emptyStringConstant", constant = ""),
|
||||
@Mapping(target = "integerConstant", constant = "14"),
|
||||
@Mapping(target = "longWrapperConstant", constant = "3001"),
|
||||
@Mapping(target = "dateConstant", dateFormat = "dd-MM-yyyy", constant = "09-01-2014"),
|
||||
@Mapping(target = "nameConstants", constant = "jack-jill-tom"),
|
||||
@Mapping(target = "country", constant = "THE_NETHERLANDS")
|
||||
})
|
||||
Target sourceToTarget(Source s);
|
||||
|
||||
Source targetToSource(Target t);
|
||||
}
|
@ -209,7 +209,7 @@ public class SourceConstantsTest {
|
||||
+ "constants.CountryEnum for property \"country\".$"),
|
||||
@Diagnostic(type = ErroneousMapper5.class,
|
||||
kind = Kind.ERROR,
|
||||
line = 43,
|
||||
line = 41,
|
||||
messageRegExp = "^Can't map \"java.lang.String \"DENMARK\"\" to \"org.mapstruct.ap.test.source."
|
||||
+ "constants.CountryEnum country\".$")
|
||||
}
|
||||
@ -217,6 +217,28 @@ public class SourceConstantsTest {
|
||||
public void errorOnNonExistingEnumConstant() throws ParseException {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IssueKey("1401")
|
||||
@WithClasses({
|
||||
Source.class,
|
||||
Target.class,
|
||||
CountryEnum.class,
|
||||
ErroneousMapper6.class,
|
||||
StringListMapper.class
|
||||
})
|
||||
@ExpectedCompilationOutcome(
|
||||
value = CompilationResult.FAILED,
|
||||
diagnostics = {
|
||||
@Diagnostic(type = ErroneousMapper6.class,
|
||||
kind = Kind.ERROR,
|
||||
line = 38,
|
||||
messageRegExp = "^.*Can't map \"java.lang.String \"3001\"\" to \"java.lang.Long "
|
||||
+ "longWrapperConstant\".*$")
|
||||
}
|
||||
)
|
||||
public void cannotMapIntConstantToLong() throws ParseException {
|
||||
}
|
||||
|
||||
private Date getDate(String format, String date) throws ParseException {
|
||||
SimpleDateFormat dateFormat = new SimpleDateFormat( format );
|
||||
Date result = dateFormat.parse( date );
|
||||
|
@ -35,7 +35,7 @@ public interface SourceTargetMapper {
|
||||
@Mapping(target = "stringConstant", constant = "stringConstant"),
|
||||
@Mapping(target = "emptyStringConstant", constant = ""),
|
||||
@Mapping(target = "integerConstant", constant = "14"),
|
||||
@Mapping(target = "longWrapperConstant", constant = "3001"),
|
||||
@Mapping(target = "longWrapperConstant", constant = "3001L"),
|
||||
@Mapping(target = "dateConstant", dateFormat = "dd-MM-yyyy", constant = "09-01-2014"),
|
||||
@Mapping(target = "nameConstants", constant = "jack-jill-tom"),
|
||||
@Mapping(target = "country", constant = "THE_NETHERLANDS")
|
||||
|
Loading…
x
Reference in New Issue
Block a user