/* * 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 ); } }