/*
* JBoss, Home of Professional Open Source
* Copyright 2006, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.metadata.spi.signature;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
/**
* Signature.
*
* @author Adrian Brock
* @version $Revision: 1.1 $
*/
public class Signature
{
/** No Name */
public static final String NO_NAME = "?%NO_NAME%?";
/** No Parameters */
public static final String[] NO_PARAMETERS = new String[0];
/** No Parameters Types */
public static final Class[] NO_PARAMETER_TYPES = new Class[0];
/** The name */
private String name;
/** The parameters */
private String[] parameters;
/** The parameter types */
private Class[] parameterTypes;
/** The cached hashcode */
private transient int cachedHashCode = Integer.MIN_VALUE;
/** The primitive types indexed by names */
private static final Map primitiveTypes = new HashMap();
private static final Map primitiveArrayTypes = new HashMap();
static
{
primitiveTypes.put(Byte.TYPE.getName(), Byte.TYPE);
primitiveTypes.put(Boolean.TYPE.getName(), Boolean.TYPE);
primitiveTypes.put(Character.TYPE.getName(), Character.TYPE);
primitiveTypes.put(Double.TYPE.getName(), Double.TYPE);
primitiveTypes.put(Float.TYPE.getName(), Float.TYPE);
primitiveTypes.put(Integer.TYPE.getName(), Integer.TYPE);
primitiveTypes.put(Long.TYPE.getName(), Long.TYPE);
primitiveTypes.put(Short.TYPE.getName(), Short.TYPE);
primitiveArrayTypes.put(Byte.TYPE.getName(), "B");
primitiveArrayTypes.put(Boolean.TYPE.getName(), "Z");
primitiveArrayTypes.put(Character.TYPE.getName(), "C");
primitiveArrayTypes.put(Double.TYPE.getName(), "D");
primitiveArrayTypes.put(Float.TYPE.getName(), "F");
primitiveArrayTypes.put(Integer.TYPE.getName(), "I");
primitiveArrayTypes.put(Long.TYPE.getName(), "J");
primitiveArrayTypes.put(Short.TYPE.getName(), "S");
}
/**
* Convert classes to string
*
* @param parameters the parameters as classes
* @return the parameters as strings
*/
private static String[] classesToStrings(Class... parameters)
{
if (parameters == null || parameters.length == 0)
return NO_PARAMETERS;
String[] result = new String[parameters.length];
for (int i = 0; i < result.length; ++i)
{
if (parameters[i] == null)
throw new IllegalArgumentException("Null class");
result[i] = parameters[i].getName();
}
return result;
}
/**
* Convert classes to string
*
* @param clazz the reference class
* @param parameters the parameters as strings
* @return the parameters as classes
*/
private static Class[] stringsToClasses(Class clazz, String... parameters)
{
if (clazz == null)
throw new IllegalArgumentException("Null clazz");
ClassLoader cl = clazz.getClassLoader();
if (cl == null)
{
cl = Class.class.getClassLoader();
if (cl == null)
{
//Bootstrap classloader was represented as null, use the tcl
cl = Thread.currentThread().getContextClassLoader();
}
}
return stringsToClasses(cl, parameters);
}
/**
* Convert classes to string
*
* @param cl the classloader
* @param parameters the parameters as strings
* @return the parameters as classes
*/
private static Class[] stringsToClasses(ClassLoader cl, String... parameters)
{
if (cl == null)
throw new IllegalArgumentException("Null classloader");
if (parameters == null || parameters.length == 0)
return NO_PARAMETER_TYPES;
Class[] result = new Class[parameters.length];
for (int i = 0; i < result.length; ++i)
{
String param = parameters[i];
int index = param.lastIndexOf('[');
if (index >= 0)
{
//For arrays we will want to load the class, the ArrayInfoImpl generates names in an invalid format, resolve this here
String primitiveCandidate = param.substring(index + 1);
String componentType = primitiveArrayTypes.get(primitiveCandidate);
if (componentType != null)
{
param = param.substring(0, index + 1) + componentType;
}
}
else
{
Class primitive = primitiveTypes.get(param);
if (primitive != null)
{
result[i] = primitive;
continue;
}
}
try
{
result[i] = Class.forName(param, false, cl);
//result[i] = cl.loadClass(param);
}
catch (ClassNotFoundException e)
{
throw new IllegalStateException("Class not found: " + parameters[i], e);
}
}
return result;
}
/**
* Create a new Signature.
*/
public Signature()
{
this(NO_NAME, NO_PARAMETER_TYPES, NO_PARAMETERS);
}
/**
* Create a new Signature.
*
* @param name the name
*/
public Signature(String name)
{
this(name, null, NO_PARAMETERS);
}
/**
* Create a new Signature.
*
* @param parameters the parameters
*/
public Signature(String... parameters)
{
this(NO_NAME, null, parameters);
}
/**
* Create a new Signature.
*
* @param parameters the parameters
*/
public Signature(Class... parameters)
{
this(NO_NAME, parameters, null);
}
/**
* Create a new Signature.
*
* @param name the name
* @param parameters the parameters
*/
public Signature(String name, Class... parameters)
{
this(name, parameters, null);
}
/**
* Create a new Signature.
*
* @param name the name
* @param parameters the parameters
*/
public Signature(String name, String... parameters)
{
this(name, null, parameters);
}
/**
* Create a new Signature.
*
* @param name the name
* @param parameterTypes the parameterTypes
* @param parameters the parameters
*/
private Signature(String name, Class[] parameterTypes, String[] parameters)
{
this.name = name;
this.parameters = parameters;
this.parameterTypes = parameterTypes;
if (name == null)
this.name = NO_NAME;
if (parameters == null)
this.parameters = classesToStrings(parameterTypes);
for (int i = 0; i < this.parameters.length; ++i)
{
if (this.parameters[i] == null)
throw new IllegalArgumentException("Null parameter");
}
}
/**
* Get the name.
*
* @return the name.
*/
public String getName()
{
return name;
}
/**
* Get the parameters.
*
* @return the parameters.
*/
public String[] getParameters()
{
return parameters;
}
/**
* Get the parameter types.
*
* @param clazz the reference class
* @return the parameter types.
*/
public Class[] getParametersTypes(Class clazz)
{
if (parameterTypes == null)
return stringsToClasses(clazz, parameters);
return parameterTypes;
}
public boolean equals(Object obj)
{
if (obj == this)
return true;
if (obj == null || obj instanceof Signature == false)
return false;
Signature other = (Signature) obj;
if (getName().equals(other.getName()) == false)
return false;
if (parameters.length != other.parameters.length)
return false;
for (int i = 0; i < parameters.length; ++i)
{
if (parameters[i].equals(other.parameters[i]) == false)
return false;
}
return true;
}
public int hashCode()
{
if (cachedHashCode == Integer.MIN_VALUE)
cachedHashCode = toString().hashCode();
return cachedHashCode;
}
public String toString()
{
StringBuilder builder = new StringBuilder();
internalToString(builder);
return builder.toString();
}
/**
* Build the to String
*
* @param builder the builder to use
*/
protected void internalToString(StringBuilder builder)
{
if (name != null)
builder.append(name);
if (parameters != null)
builder.append(Arrays.asList(parameters));
}
}