blob: 5698ee8a44c5efd51fd0c8bdb91cacbf8083edfe [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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
<<<<<<< Updated upstream
*
* 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
=======
*
* https://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
>>>>>>> Stashed changes
* limitations under the License.
*/
package org.apache.jdo.tck.util.signature;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/** A helper class for translating between Java user type names and reflection type names. */
public class TypeHelper {
/** Error message for format errors with a user type name. */
private static final String MSG_ILLEGAL_USR_TYPE = "illegal user type name: ";
/** Error message for format errors with a reflection type name. */
private static final String MSG_ILLEGAL_RFL_TYPE = "illegal reflection type name: ";
/** Throws an IllegalArgumentException if a given condition is violated. */
private static void check(boolean cond, String msg) {
if (!cond) throw new IllegalArgumentException(msg);
}
/** Maps primitive reflection type names to (Java) user names. */
private static final Map<String, String> userTypeNames = new HashMap<>();
/** Maps primitive (Java) user type names to reflection names. */
private static final Map<String, String> reflectionTypeNames = new HashMap<>();
/** Maps primitive type names to class objects. */
private static final Map<String, Class<?>> primitiveClasses = new HashMap<>();
// initializes the type maps
static {
userTypeNames.put("B", "byte");
userTypeNames.put("C", "char");
userTypeNames.put("D", "double");
userTypeNames.put("F", "float");
userTypeNames.put("I", "int");
userTypeNames.put("J", "long");
userTypeNames.put("S", "short");
userTypeNames.put("Z", "boolean");
userTypeNames.put("V", "void");
for (final Map.Entry<String, String> e : userTypeNames.entrySet()) {
reflectionTypeNames.put(e.getValue(), e.getKey());
}
primitiveClasses.put("byte", byte.class);
primitiveClasses.put("char", char.class);
primitiveClasses.put("double", double.class);
primitiveClasses.put("float", float.class);
primitiveClasses.put("int", int.class);
primitiveClasses.put("long", long.class);
primitiveClasses.put("short", short.class);
primitiveClasses.put("boolean", boolean.class);
primitiveClasses.put("void", void.class);
}
/**
* Returns the (Java) user name for a reflection type name.
*
* @param name typed name
* @return user name for a reflection type name
*/
public static String userTypeName(String name) {
check(name != null, MSG_ILLEGAL_RFL_TYPE + name);
// count array dimensions from start
final int n = name.length();
check(n > 0, MSG_ILLEGAL_RFL_TYPE + name);
int i = 0;
final StringBuilder sb = new StringBuilder();
while (name.charAt(i) == '[') {
sb.append("[]");
i++;
check(i < n, MSG_ILLEGAL_RFL_TYPE + name);
}
// no translation of primitive type names if not an array type
if (i == 0) {
return name;
}
// translate and recompose name
final String s;
if (name.charAt(i) == 'L') {
check(name.endsWith(";"), MSG_ILLEGAL_RFL_TYPE + name);
s = name.substring(i + 1, n - 1);
} else {
s = userTypeNames.get(name.substring(i));
check(s != null, MSG_ILLEGAL_RFL_TYPE + name);
}
return (s + sb);
}
/**
* Returns the (Java) user names for reflection type names.
*
* @param names type names
* @return the (Java) user names for reflection type names.
*/
public static String[] userTypeNames(String[] names) {
final String[] u = new String[names.length];
for (int i = names.length - 1; i >= 0; i--) {
u[i] = userTypeName(names[i]);
}
return u;
}
/**
* Returns the reflection name for a (Java) user type name.
*
* @param name type name
* @return reflection name for a (Java) user type name
*/
public static String reflectionTypeName(String name) {
check(name != null, MSG_ILLEGAL_USR_TYPE + name);
// count array dimensions from end
final int n = name.length();
check(n > 0, MSG_ILLEGAL_USR_TYPE + name);
int i = n - 1;
final StringBuilder sb = new StringBuilder();
while (name.charAt(i) == ']') {
i--;
check(name.charAt(i) == '[', MSG_ILLEGAL_USR_TYPE + name);
sb.append("[");
i--;
check(i >= 0, MSG_ILLEGAL_USR_TYPE + name);
}
// no translation of primitive type names if not an array type
if (++i == n) {
return name;
}
// translate and recompose name
final String s = name.substring(0, i);
final String p = reflectionTypeNames.get(s);
return sb.append(p != null ? p : "L" + s + ";").toString();
}
/**
* Returns the (Java) user names for reflection type names.
*
* @param names type names
* @return the (Java) user names for reflection type names.
*/
public static String[] reflectionTypeNames(String[] names) {
final String[] r = new String[names.length];
for (int i = names.length - 1; i >= 0; i--) {
r[i] = reflectionTypeName(names[i]);
}
return r;
}
/**
* Returns the class object for a primitive type name, or <code>null</code> if the name does not
* denote a primitive type (class objects of primitive types cannot be loaded with reflection).
*
* @param name type name
* @return class object
*/
public static Class<?> primitiveClass(String name) {
return primitiveClasses.get(name);
}
/**
* Tests if a name denotes a primitive type.
*
* @param name type name
* @return true if a name denotes a primitive type.
*/
public static boolean isPrimitive(String name) {
return primitiveClasses.containsKey(name);
}
/**
* Returns the component type name of a (Java) user type name.
*
* @param name type name
* @return component type name of a (Java) user type name
*/
public static String componentUserTypeName(String name) {
check(name != null, MSG_ILLEGAL_USR_TYPE + name);
final int n = name.length();
check(n > 0, MSG_ILLEGAL_USR_TYPE + name);
final int i = name.indexOf('[');
if (i >= 0) {
check(i > 0, MSG_ILLEGAL_USR_TYPE + name);
name = name.substring(0, i);
}
return name;
}
/**
* Returns the <code>java.lang.</code>-qualified name for a given unqualified (Java) user type
* name.
*
* @param name type name
* @return qualified name
*/
public static String qualifiedUserTypeName(String name) {
final String c = componentUserTypeName(name);
return ((isPrimitive(c) || c.indexOf('.') >= 0) ? name : "java.lang." + name);
}
/**
* Returns the <code>java.lang.</code>-qualified names for given unqualified (Java) user type
* names.
*
* @param names type names
* @return qualified name
*/
public static String[] qualifiedUserTypeNames(String[] names) {
final String[] q = new String[names.length];
for (int i = names.length - 1; i >= 0; i--) {
q[i] = qualifiedUserTypeName(names[i]);
}
return q;
}
/**
* Compares a type name with a class objects for equality in the name.
*
* @param userTypeName type name
* @param cls class object
* @return true if name matches
*/
public static boolean isNameMatch(String userTypeName, Class<?> cls) {
final String c = (cls == null ? null : userTypeName(cls.getName()));
return (userTypeName == null ? (c == null) : userTypeName.equals(c));
}
/**
* Compares an array of type names with an array of class objects for set-equality in the names
* (i.e., ignoring order).
*
* @param userTypeName type names
* @param cls class objects
* @return true if names matches
*/
public static boolean isNameMatch(String[] userTypeName, Class<?>[] cls) {
final Set<String> s = new HashSet<>(Arrays.asList(userTypeName));
for (int i = cls.length - 1; i >= 0; i--) {
if (!s.remove(userTypeName(cls[i].getName()))) {
return false;
}
}
return s.isEmpty();
}
}