/*
* Copyright 2015 Nicolas Morel
*
* 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 com.github.nmorel.gwtjackson.rebind.writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import com.google.gwt.core.ext.typeinfo.JArrayType;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.JGenericType;
import com.google.gwt.core.ext.typeinfo.JParameterizedType;
import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
import com.google.gwt.core.ext.typeinfo.JType;
import com.google.gwt.core.ext.typeinfo.JTypeParameter;
import com.google.gwt.core.ext.typeinfo.JWildcardType;
import com.google.gwt.dev.util.collect.HashSet;
import com.squareup.javapoet.ArrayTypeName;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeVariableName;
import com.squareup.javapoet.WildcardTypeName;
/**
* Helper class to convert {@link JType} into {@link TypeName}
*
* @author Nicolas Morel
* @version $Id: $
*/
public final class JTypeName {
private JTypeName() {}
/**
* Default wildcard : ?
*/
public static final WildcardTypeName DEFAULT_WILDCARD = WildcardTypeName.subtypeOf( Object.class );
private static final ClassName BOOLEAN_NAME = ClassName.get( Boolean.class );
private static final ClassName BYTE_NAME = ClassName.get( Byte.class );
private static final ClassName SHORT_NAME = ClassName.get( Short.class );
private static final ClassName INTEGER_NAME = ClassName.get( Integer.class );
private static final ClassName LONG_NAME = ClassName.get( Long.class );
private static final ClassName CHARACTER_NAME = ClassName.get( Character.class );
private static final ClassName FLOAT_NAME = ClassName.get( Float.class );
private static final ClassName DOUBLE_NAME = ClassName.get( Double.class );
private static final ClassName VOID_NAME = ClassName.get( Void.class );
private static final class TypeResolver {
private Set<String> resolvedTypes = new HashSet<String>();
/**
* @param type the type
*
* @return the {@link TypeName}
*/
public TypeName typeName( JType type ) {
return typeName( false, type );
}
/**
* @param boxed true if the primitive should be boxed. Useful when use in a parameterized type.
* @param type the type
*
* @return the {@link TypeName}
*/
public TypeName typeName( boolean boxed, JType type ) {
if ( null != type.isPrimitive() ) {
return primitiveName( type.isPrimitive(), boxed );
} else if ( null != type.isParameterized() ) {
return parameterizedName( type.isParameterized() );
} else if ( null != type.isGenericType() ) {
return genericName( type.isGenericType() );
} else if ( null != type.isArray() ) {
return arrayName( type.isArray() );
} else if ( null != type.isTypeParameter() ) {
return typeVariableName( type.isTypeParameter() );
} else if ( null != type.isWildcard() ) {
return wildcardName( type.isWildcard() );
} else {
return className( type.isClassOrInterface() );
}
}
/**
* @param clazz the raw type
* @param types the parameters
*
* @return the {@link ParameterizedTypeName}
*/
public ParameterizedTypeName parameterizedName( Class clazz, JType... types ) {
return ParameterizedTypeName.get( ClassName.get( clazz ), typeName( true, types ) );
}
/**
* @param type type to convert
*
* @return the raw {@link TypeName} without parameter
*/
public TypeName rawName( JType type ) {
return rawName( false, type );
}
/**
* @param boxed true if the primitive should be boxed. Useful when use in a parameterized type.
* @param type type to convert
*
* @return the raw {@link TypeName} without parameter
*/
public TypeName rawName( boolean boxed, JType type ) {
if ( null != type.isPrimitive() ) {
return primitiveName( type.isPrimitive(), boxed );
} else if ( null != type.isParameterized() ) {
return className( type.isParameterized().getRawType() );
} else if ( null != type.isGenericType() ) {
return className( type.isGenericType().getRawType() );
} else if ( null != type.isArray() ) {
return arrayName( type.isArray() );
} else if ( null != type.isTypeParameter() ) {
return typeVariableName( type.isTypeParameter() );
} else {
return className( type.isClassOrInterface() );
}
}
/**
* @param types the types
*
* @return the {@link TypeName}s
*/
private TypeName[] typeName( JType... types ) {
return typeName( false, types );
}
private TypeName[] typeName( boolean boxed, JType... types ) {
TypeName[] result = new TypeName[types.length];
for ( int i = 0; i < types.length; i++ ) {
result[i] = typeName( boxed, types[i] );
}
return result;
}
private TypeName primitiveName( JPrimitiveType type, boolean boxed ) {
if ( "boolean".equals( type.getSimpleSourceName() ) ) {
return boxed ? BOOLEAN_NAME : TypeName.BOOLEAN;
} else if ( "byte".equals( type.getSimpleSourceName() ) ) {
return boxed ? BYTE_NAME : TypeName.BYTE;
} else if ( "short".equals( type.getSimpleSourceName() ) ) {
return boxed ? SHORT_NAME : TypeName.SHORT;
} else if ( "int".equals( type.getSimpleSourceName() ) ) {
return boxed ? INTEGER_NAME : TypeName.INT;
} else if ( "long".equals( type.getSimpleSourceName() ) ) {
return boxed ? LONG_NAME : TypeName.LONG;
} else if ( "char".equals( type.getSimpleSourceName() ) ) {
return boxed ? CHARACTER_NAME : TypeName.CHAR;
} else if ( "float".equals( type.getSimpleSourceName() ) ) {
return boxed ? FLOAT_NAME : TypeName.FLOAT;
} else if ( "double".equals( type.getSimpleSourceName() ) ) {
return boxed ? DOUBLE_NAME : TypeName.DOUBLE;
} else {
return boxed ? VOID_NAME : TypeName.VOID;
}
}
private ParameterizedTypeName parameterizedName( JParameterizedType type ) {
return ParameterizedTypeName.get( className( type ), typeName( true, type.getTypeArgs() ) );
}
private ParameterizedTypeName genericName( JGenericType type ) {
return ParameterizedTypeName.get( className( type ), typeName( true, type.getTypeParameters() ) );
}
private ArrayTypeName arrayName( JArrayType type ) {
return ArrayTypeName.of( typeName( type.getComponentType() ) );
}
public TypeVariableName typeVariableName( JTypeParameter type ) {
if ( resolvedTypes.contains( type.getName() ) ) {
return TypeVariableName.get( type.getName() );
} else {
resolvedTypes.add( type.getName() );
return TypeVariableName.get( type.getName(), typeName( type.getBounds() ) );
}
}
private WildcardTypeName wildcardName( JWildcardType type ) {
switch ( type.getBoundType() ) {
case SUPER:
return WildcardTypeName.supertypeOf( typeName( type.getFirstBound() ) );
default:
return WildcardTypeName.subtypeOf( typeName( type.getFirstBound() ) );
}
}
private ClassName className( JClassType type ) {
JClassType enclosingType = type.getEnclosingType();
if ( null == enclosingType ) {
return ClassName.get( type.getPackage()
.getName(), type.getSimpleSourceName() );
}
// We look for all enclosing types and add them at the head.
List<String> types = new ArrayList<String>();
types.add( type.getSimpleSourceName() );
while ( null != enclosingType ) {
types.add( 0, enclosingType.getSimpleSourceName() );
enclosingType = enclosingType.getEnclosingType();
}
// The parent type is the first one. We remove it to keep only the childs.
String parentType = types.remove( 0 );
String[] childs = types.toArray( new String[types.size()] );
return ClassName.get( type.getPackage()
.getName(), parentType, childs );
}
}
/**
* <p>typeName</p>
*
* @param type the type
* @return the {@link TypeName}
*/
public static TypeName typeName( JType type ) {
return new TypeResolver().typeName( type );
}
/**
* <p>typeName</p>
*
* @param boxed true if the primitive should be boxed. Useful when use in a parameterized type.
* @param type the type
* @return the {@link TypeName}
*/
public static TypeName typeName( boolean boxed, JType type ) {
return new TypeResolver().typeName( boxed, type );
}
/**
* <p>parameterizedName</p>
*
* @param clazz the raw type
* @param types the parameters
* @return the {@link ParameterizedTypeName}
*/
public static ParameterizedTypeName parameterizedName( Class clazz, JType... types ) {
return new TypeResolver().parameterizedName( clazz, types );
}
/**
* <p>rawName</p>
*
* @param type type to convert
* @return the raw {@link TypeName} without parameter
*/
public static TypeName rawName( JType type ) {
return new TypeResolver().rawName( type );
}
/**
* <p>rawName</p>
*
* @param boxed true if the primitive should be boxed. Useful when use in a parameterized type.
* @param type type to convert
* @return the raw {@link TypeName} without parameter
*/
public static TypeName rawName( boolean boxed, JType type ) {
return new TypeResolver().rawName( boxed, type );
}
/**
* <p>typeVariableName</p>
*
* @param type type to convert
* @return the {@link TypeVariableName}
*/
public static TypeVariableName typeVariableName( JTypeParameter type ) {
return new TypeResolver().typeVariableName( type );
}
}