FieldSignature.java
package org.djutils.reflection;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.LinkedHashMap;
import java.util.Map;
import org.djutils.primitives.Primitive;
/**
* A field descriptor represents the type of a class, instance, or local variable. It is a series of characters generated by the
* grammar described at <a href = "https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html"> The Java Virtual Machine
* class File Format </a>.
* <p>
* Copyright (c) 2002-2024 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
* for project information <a href="https://djutils.org" target="_blank"> https://djutils.org</a>. The DJUTILS project is
* distributed under a three-clause BSD-style license, which can be found at
* <a href="https://djutils.org/docs/license.html" target="_blank"> https://djutils.org/docs/license.html</a>.
* </p>
* @author Peter Jacobs, Niels Lang, Alexander Verbraeck
*/
public class FieldSignature implements Serializable
{
/** The default serial version UID for serializable classes. */
private static final long serialVersionUID = 20191230L;
/** the CAHCHe. */
private static final Map<String, Class<?>> CACHE = new LinkedHashMap<String, Class<?>>();
/** the value of the field descriptor. */
private String value;
/**
* constructs a new FieldSignature.
* @param value String; the value of the descriptor
*/
public FieldSignature(final String value)
{
this.value = value;
}
/**
* constructs a new FieldSignature.
* @param clazz Class<?>; The class
*/
public FieldSignature(final Class<?> clazz)
{
this(FieldSignature.toDescriptor(clazz));
}
/**
* @return Returns the value of the field descriptor
*/
public String getStringValue()
{
return this.value;
}
/**
* @return Returns the value of the field descriptor
* @throws ClassNotFoundException if the class cannot be found.
*/
public Class<?> getClassValue() throws ClassNotFoundException
{
return FieldSignature.toClass(this.value);
}
@Override
public String toString()
{
return this.value;
}
/**
* converts an array of fields to its descriptor.
* @param classes Class<?>[]; the classes to represent
* @return String the descriptor String
*/
public static final String toDescriptor(final Class<?>[] classes)
{
StringBuilder result = new StringBuilder();
for (int i = 0; i < classes.length; i++)
{
result.append(FieldSignature.toDescriptor(classes[i]));
}
return result.toString();
}
/**
* converts a field to its descriptor.
* @param clazz Class<?>; the clazz to represent
* @return String the descriptor String
*/
public static final String toDescriptor(final Class<?> clazz)
{
if (clazz.getName().startsWith("["))
{
return clazz.getName().replace('.', '/');
}
if (clazz.isPrimitive())
{
if (clazz.equals(int.class))
{
return "I";
}
if (clazz.equals(double.class))
{
return "D";
}
if (clazz.equals(boolean.class))
{
return "Z";
}
if (clazz.equals(char.class))
{
return "C";
}
if (clazz.equals(byte.class))
{
return "B";
}
if (clazz.equals(float.class))
{
return "F";
}
if (clazz.equals(long.class))
{
return "J";
}
if (clazz.equals(short.class))
{
return "S";
}
return "V";
}
return "L" + clazz.getName().replace('.', '/') + ";";
}
/**
* converts a fieldDescriptor to its class representation.
* @param descriptor String; the descriptor
* @return Class the class
* @throws ClassNotFoundException on failure
*/
public static final Class<?> toClass(final String descriptor) throws ClassNotFoundException
{
if (FieldSignature.CACHE.containsKey(descriptor))
{
return FieldSignature.CACHE.get(descriptor);
}
String className = descriptor;
Class<?> result = null;
int array = 0;
while (className.charAt(array) == '[')
{
array++;
}
className = className.substring(array);
if (className.startsWith("L"))
{
className = className.replaceAll("/", ".");
className = className.substring(1, className.length() - 1);
try
{
result = Class.forName(className);
}
catch (Exception exception)
{
result = Class.forName(className, true, Thread.currentThread().getContextClassLoader());
}
}
else
{
result = Primitive.forName(className);
}
if (result == null && !descriptor.startsWith("["))
{
// For some reason not all classes start with L and end with ;
return FieldSignature.toClass("L" + descriptor + ";");
}
if (array == 0)
{
FieldSignature.CACHE.put(descriptor, result);
return result;
}
try
{
int[] dimensions = new int[array];
result = Array.newInstance(result, dimensions).getClass();
}
catch (Exception exception)
{
throw new ClassNotFoundException(result + " class not found");
}
FieldSignature.CACHE.put(descriptor, result);
return result;
}
}