blob: 3a94acea21b573a292c961de61fa94dfdee18cc3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2010 Oracle. 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:
* Oracle - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.utility.internal;
import java.io.PrintWriter;
import java.io.Serializable;
import org.eclipse.jpt.utility.JavaType;
/**
* Straightforward implementation of the {@link JavaType} interface.
*/
public final class SimpleJavaType
implements JavaType, Cloneable, Serializable
{
/**
* store the type as a name, so we can reference classes
* that are not loaded
*/
private final String elementTypeName;
/**
* non-array types have an array depth of zero
*/
private final int arrayDepth;
private static final String BRACKETS = "[]"; //$NON-NLS-1$
private static final long serialVersionUID = 1L;
// ********** constructors **********
/**
* Construct a Java type with the specified element type and array depth.
*/
public SimpleJavaType(String elementTypeName, int arrayDepth) {
super();
if ((elementTypeName == null) || (elementTypeName.length() == 0)) {
throw new IllegalArgumentException("The element type name is required."); //$NON-NLS-1$
}
if (ClassName.getArrayDepth(elementTypeName) != 0) { // e.g. "[Ljava.lang.Object;"
throw new IllegalArgumentException("The element type must not be an array: " + elementTypeName + '.'); //$NON-NLS-1$
}
if (arrayDepth < 0) {
throw new IllegalArgumentException("The array depth must be greater than or equal to zero: " + arrayDepth + '.'); //$NON-NLS-1$
}
if (elementTypeName.equals(void.class.getName()) && (arrayDepth != 0)) {
throw new IllegalArgumentException("'void' must have an array depth of zero: " + arrayDepth + '.'); //$NON-NLS-1$
}
this.elementTypeName = elementTypeName;
this.arrayDepth = arrayDepth;
}
/**
* Construct a Java type for the specified class.
* The class name can be in one of the following forms:<ul><code>
* <li>java.lang.Object
* <li>int
* <li>java.util.Map$Entry
* <li>[Ljava.lang.Object;
* <li>[I
* <li>[Ljava.util.Map$Entry;
* </code></ul>
*/
public SimpleJavaType(String javaClassName) {
this(ClassName.getElementTypeName(javaClassName), ClassName.getArrayDepth(javaClassName));
}
/**
* Construct a Java type for the specified class.
*/
public SimpleJavaType(Class<?> javaClass) {
this(javaClass.getName());
}
// ********** accessors **********
public String getElementTypeName() {
return this.elementTypeName;
}
public int getArrayDepth() {
return this.arrayDepth;
}
// ********** queries **********
public boolean isArray() {
return this.arrayDepth > 0;
}
public boolean isPrimitive() {
return (this.arrayDepth == 0) && ClassName.isPrimitive(this.elementTypeName);
}
public boolean isPrimitiveWrapper() {
return (this.arrayDepth == 0) && ClassName.isPrimitiveWrapper(this.elementTypeName);
}
public boolean isVariablePrimitive() {
return (this.arrayDepth == 0) && ClassName.isVariablePrimitive(this.elementTypeName);
}
public boolean isVariablePrimitiveWrapper() {
return (this.arrayDepth == 0) && ClassName.isVariablePrimitiveWrapper(this.elementTypeName);
}
public Class<?> getJavaClass() throws ClassNotFoundException {
return ReflectionTools.getClassForTypeDeclaration(this.elementTypeName, this.arrayDepth);
}
public String getJavaClassName() {
return ReflectionTools.getClassNameForTypeDeclaration(this.elementTypeName, this.arrayDepth);
}
// ********** comparison **********
public boolean equals(String otherElementTypeName, int otherArrayDepth) {
return (this.arrayDepth == otherArrayDepth)
&& this.elementTypeName.equals(otherElementTypeName);
}
public boolean describes(String className) {
return this.equals(ClassName.getElementTypeName(className), ClassName.getArrayDepth(className));
}
public boolean describes(Class<?> javaClass) {
return this.describes(javaClass.getName());
}
public boolean equals(JavaType other) {
return this.equals(other.getElementTypeName(), other.getArrayDepth());
}
@Override
public boolean equals(Object o) {
return (this == o) ? true : (o instanceof JavaType) ? this.equals((JavaType) o) : false;
}
@Override
public int hashCode() {
return this.elementTypeName.hashCode() ^ this.arrayDepth;
}
// ********** printing and displaying **********
public String declaration() {
if (this.arrayDepth == 0) {
return this.getElementTypeNameDeclaration();
}
StringBuilder sb = new StringBuilder(this.elementTypeName.length() + (2 * this.arrayDepth));
this.appendDeclarationTo(sb);
return sb.toString();
}
public void appendDeclarationTo(StringBuilder sb) {
sb.append(this.getElementTypeNameDeclaration());
for (int i = this.arrayDepth; i-- > 0; ) {
sb.append(BRACKETS);
}
}
public void printDeclarationOn(PrintWriter pw) {
pw.print(this.getElementTypeNameDeclaration());
for (int i = this.arrayDepth; i-- > 0; ) {
pw.print(BRACKETS);
}
}
/**
* The <code>'$'</code> version of the name is used in {@link Class#forName(String)},
* but the <code>'.'</code> version of the name is used in source code.
* Very irritating....
*/
private String getElementTypeNameDeclaration() {
return this.elementTypeName.replace('$', '.');
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(this.getClass().getSimpleName());
sb.append('(');
this.appendDeclarationTo(sb);
sb.append(')');
return sb.toString();
}
// ********** cloning **********
@Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException ex) {
throw new InternalError();
}
}
}