blob: 4c5718f89603d7c70df974d8297d07a9b9f5d1a1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006 Oracle Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Cameron Bateman/Oracle - initial API and implementation
*
********************************************************************************/
package org.eclipse.jst.jsf.common.internal.types;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.eclipse.jdt.core.Signature;
/**
* Transforms one CompositeType to another according to particular
* transform rules.
*
* In general, every transformation should be of the form:
*
* CompositeType transform(CompositeType original, other inputs...);
*
* @author cbateman
*
*/
public class TypeTransformer
{
private final static Map boxConversions = new HashMap();
private final static Map unBoxConversions = new HashMap();
static
{
// see jdt.core.Signature or JVM link spec for more details
boxConversions.put("B", "Ljava.lang.Byte;"); //$NON-NLS-1$//$NON-NLS-2$
boxConversions.put("C", "Ljava.lang.Character;"); //$NON-NLS-1$ //$NON-NLS-2$
boxConversions.put("D", "Ljava.lang.Double;"); //$NON-NLS-1$ //$NON-NLS-2$
boxConversions.put("F", "Ljava.lang.Float;"); //$NON-NLS-1$ //$NON-NLS-2$
boxConversions.put("I", "Ljava.lang.Integer;"); //$NON-NLS-1$ //$NON-NLS-2$
boxConversions.put("J", "Ljava.lang.Long;"); //$NON-NLS-1$ //$NON-NLS-2$
boxConversions.put("S", "Ljava.lang.Short;"); //$NON-NLS-1$ //$NON-NLS-2$
boxConversions.put("Z", "Ljava.lang.Boolean;"); //$NON-NLS-1$ //$NON-NLS-2$
// don't box V
boxConversions.put("V", "V"); //$NON-NLS-1$ //$NON-NLS-2$
// invert hte box conversions
for (final Iterator it = boxConversions.keySet().iterator(); it.hasNext();)
{
final String newValue = (String) it.next();
final String newKey = (String) boxConversions.get(newValue);
if (unBoxConversions.put(newKey, newValue) != null)
{
// if put returns non-null then we have replaced a key
// added on a previous iteration. This implies
// that box mappings are no longer one-to-one
throw new AssertionError("Duplicated boxing value"); //$NON-NLS-1$
}
}
}
/**
* @param compositeType
* @return an equivilent form of compositeType with all primitive type
* signatures converted to their fully qualified boxed equivilent but
* otherwise unchanged.
*
* Example: J -> Ljava.lang.Long;
*/
public static CompositeType transformBoxPrimitives(CompositeType compositeType)
{
String[] signatures = compositeType.getSignatures();
String[] newsignatures = new String[signatures.length];
for (int i = 0; i < signatures.length; i++)
{
newsignatures[i] = transformBoxPrimitives(signatures[i]);
}
return new CompositeType(newsignatures, compositeType.getAssignmentTypeMask());
}
/**
* Performs boxing for a single typeSignature string
* @param curSignature
* @return the boxed signature
*/
public static String transformBoxPrimitives(final String curSignature)
{
String newSignature = curSignature;
// first determine if we have a type or method signature
try
{
int kind = Signature.getTypeSignatureKind(curSignature);
// interested in base types, since these need boxing
if (kind == Signature.BASE_TYPE_SIGNATURE)
{
// grab the box for the primitive
newSignature = (String) boxConversions.get(curSignature);
}
else if (kind == Signature.ARRAY_TYPE_SIGNATURE)
{
// check if it's array of primitives
final String baseType = Signature.getElementType(curSignature);
if (Signature.getTypeSignatureKind(baseType) == Signature.BASE_TYPE_SIGNATURE)
{
// it is, so box it
final String newBaseType = (String) boxConversions.get(baseType);
final int numBraces = Signature.getArrayCount(curSignature);
newSignature = ""; //$NON-NLS-1$
for (int j = 0; j < numBraces; j++)
{
newSignature += "["; //$NON-NLS-1$
}
newSignature += newBaseType;
}
}
}
catch (IllegalArgumentException e)
{
// signature was not a type signature, so must be a method sig
// do nothing: don't box method types
}
return newSignature;
}
/**
* Performs the exact inverse of transformBoxPrimitives -- takes all
* boxing type signatures and replaces them with their primitive equivilent
* @param compositeType
* @return a new composite with all boxed primitives unboxed
*/
public static CompositeType transformUnboxPrimitives(CompositeType compositeType)
{
String[] signatures = compositeType.getSignatures();
String[] newsignatures = new String[signatures.length];
for (int i = 0; i < signatures.length; i++)
{
newsignatures[i] = transformUnboxPrimitives(signatures[i]);
}
return new CompositeType(newsignatures, compositeType.getAssignmentTypeMask());
}
/**
* Performs unboxing for a single typeSignature string
*
* @param typeSignature
* @return the transformed signature
*/
public static String transformUnboxPrimitives(final String typeSignature)
{
String newSignature = typeSignature;
// first determine if we have a type or method signature
try
{
int kind = Signature.getTypeSignatureKind(typeSignature);
// interested in class types, since these need boxing
if (kind == Signature.CLASS_TYPE_SIGNATURE)
{
// grab the box for the primitive
String checkForUnbox = (String) unBoxConversions.get(typeSignature);
if (checkForUnbox != null)
{
newSignature = checkForUnbox;
}
}
else if (kind == Signature.ARRAY_TYPE_SIGNATURE)
{
// check if it's array of objects
final String baseType = Signature.getElementType(typeSignature);
if (Signature.getTypeSignatureKind(baseType) == Signature.CLASS_TYPE_SIGNATURE)
{
// it is, so unbox it
final String newBaseTypeCandidate = (String) unBoxConversions.get(baseType);
if (newBaseTypeCandidate != null)
{
final int numBraces = Signature.getArrayCount(typeSignature);
newSignature = ""; //$NON-NLS-1$
for (int j = 0; j < numBraces; j++)
{
newSignature += "["; //$NON-NLS-1$
}
newSignature += newBaseTypeCandidate;
}
}
}
}
catch (IllegalArgumentException e)
{
// signature was not a type signature, so must be a method sig
// do nothing: don't box method types
}
return newSignature;
}
}