/******************************************************************************* * 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.common.utility.internal; import java.io.PrintWriter; import java.io.Serializable; import org.eclipse.jpt.common.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: */ 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 '$' version of the name is used in {@link Class#forName(String)}, * but the '.' 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(); } } }