blob: 9037371b39d47717f5f2e3a902533d290e4d9963 [file] [log] [blame]
/*
* Copyright 2006 Google Inc.
*
* Licensed 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
*
* 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 limitations under
* the License.
*/
package java.lang;
import com.google.gwt.core.client.JavaScriptObject;
/**
* Generally unsupported. This class is provided so that the GWT compiler can
* choke down class literal references.
*
* @param <T> the type of the object
*/
public final class Class<T> {
private static final int PRIMITIVE = 0x00000001;
private static final int INTERFACE = 0x00000002;
private static final int ARRAY = 0x00000004;
private static final int ENUM = 0x00000008;
static native String asString(int number) /*-{
// for primitives, the seedId isn't a number, but a string like ' Z'
return typeof(number) == 'number' ? "S" + (number < 0 ? -number : number) : number;
}-*/;
/**
* Create a Class object for an array.
*
* @skip
*/
static <T> Class<T> createForArray(String packageName, String className,
int seedId, Class<?> componentType) {
// Initialize here to avoid method inliner
Class<T> clazz = new Class<T>();
setName(clazz, packageName, className, seedId != 0 ? -seedId : 0);
clazz.modifiers = ARRAY;
clazz.superclass = Object.class;
clazz.componentType = componentType;
return clazz;
}
/**
* Create a Class object for a class.
*
* @skip
*/
static <T> Class<T> createForClass(String packageName, String className,
int seedId, Class<? super T> superclass) {
// Initialize here to avoid method inliner
Class<T> clazz = new Class<T>();
setName(clazz, packageName, className, seedId);
clazz.superclass = superclass;
return clazz;
}
/**
* Create a Class object for an enum.
*
* @skip
*/
static <T> Class<T> createForEnum(String packageName, String className,
int seedId, Class<? super T> superclass,
JavaScriptObject enumConstantsFunc, JavaScriptObject enumValueOfFunc) {
// Initialize here to avoid method inliner
Class<T> clazz = new Class<T>();
setName(clazz, packageName, className, seedId);
clazz.modifiers = (enumConstantsFunc != null) ? ENUM : 0;
clazz.superclass = clazz.enumSuperclass = superclass;
clazz.enumConstantsFunc = enumConstantsFunc;
clazz.enumValueOfFunc = enumValueOfFunc;
return clazz;
}
/**
* Create a Class object for an interface.
*
* @skip
*/
static <T> Class<T> createForInterface(String packageName, String className) {
// Initialize here to avoid method inliner
Class<T> clazz = new Class<T>();
setName(clazz, packageName, className, 0);
clazz.modifiers = INTERFACE;
return clazz;
}
/**
* Create a Class object for a primitive.
*
* @skip
*/
static Class<?> createForPrimitive(String packageName, String className,
int seedId) {
// Initialize here to avoid method inliner
Class<?> clazz = new Class<Object>();
setName(clazz, packageName, className, seedId);
clazz.modifiers = PRIMITIVE;
return clazz;
}
/**
* Used by {@link WebModePayloadSink} to create uninitialized instances.
*/
static native JavaScriptObject getSeedFunction(Class<?> clazz) /*-{
var func = @com.google.gwt.lang.SeedUtil::seedTable[clazz.@java.lang.Class::seedId];
clazz = null; // HACK: prevent pruning via inlining by using param as lvalue
return func;
}-*/;
static boolean isClassMetadataEnabled() {
// This body may be replaced by the compiler
return true;
}
/**
* null or 0 implies lack of seed function / non-instantiable type
*/
static native boolean isInstantiable(int seedId) /*-{
return typeof (seedId) == 'number' && seedId > 0;
}-*/;
/**
* null implies pruned.
*/
static native boolean isInstantiableOrPrimitive(int seedId) /*-{
return seedId != null && seedId != 0;
}-*/;
/**
* Install class literal into seed.prototype.clazz field such that
* Object.getClass() returning this.clazz returns the literal. Also stores
* seedId on class literal for looking up prototypes given a literal. This
* is used for deRPC at the moment, but may be used to implement
* Class.newInstance() in the future.
*/
static native void setClassLiteral(int seedId, Class<?> clazz) /*-{
var proto;
clazz.@java.lang.Class::seedId = seedId;
// String is the exception to the usual vtable setup logic
if (seedId == 2) {
proto = String.prototype
} else {
if (seedId > 0) {
// Guarantees virtual method won't be pruned by using a JSNI ref
// This is required because deRPC needs to call it.
var seed = @java.lang.Class::getSeedFunction(Ljava/lang/Class;)(clazz);
// A class literal may be referenced prior to an async-loaded vtable setup
// For example, class literal lives in inital fragment,
// but type is instantiated in another fragment
if (seed) {
proto = seed.prototype;
} else {
// Leave a place holder for now to be filled in by __defineSeed__ later
seed = @com.google.gwt.lang.SeedUtil::seedTable[seedId] = function(){};
seed.@java.lang.Object::___clazz = clazz;
return;
}
} else {
return;
}
}
proto.@java.lang.Object::___clazz = clazz;
}-*/;
/**
* The seedId parameter can take on the following values:
* > 0 => type is instantiable class
* < 0 => type is instantiable array
* null => type is not instantiable
* string => type is primitive
*/
static void setName(Class<?> clazz, String packageName, String className,
int seedId) {
if (clazz.isClassMetadataEnabled()) {
clazz.typeName = packageName + className;
clazz.simpleName = className;
} else {
/*
* The initial "" + in the below code is to prevent clazz.hashCode() from
* being autoboxed. The class literal creation code is run very early
* during application start up, before class Integer has been initialized.
*/
clazz.typeName = "Class$"
+ (isInstantiableOrPrimitive(seedId) ? asString(seedId) : "" + clazz.hashCode());
clazz.simpleName = clazz.typeName;
}
if (isInstantiable(seedId)) {
setClassLiteral(seedId, clazz);
}
}
JavaScriptObject enumValueOfFunc;
int modifiers;
private Class<?> componentType;
@SuppressWarnings("unused")
private JavaScriptObject enumConstantsFunc;
private Class<? super T> enumSuperclass;
private Class<? super T> superclass;
private String simpleName;
private String typeName;
private int seedId;
/**
* Not publicly instantiable.
*
* @skip
*/
private Class() {
}
public boolean desiredAssertionStatus() {
// This body is ignored by the JJS compiler and a new one is
// synthesized at compile-time based on the actual compilation arguments.
return false;
}
public Class<?> getComponentType() {
return componentType;
}
public native T[] getEnumConstants() /*-{
return this.@java.lang.Class::enumConstantsFunc
&& (this.@java.lang.Class::enumConstantsFunc)();
}-*/;
public String getName() {
return typeName;
}
public String getSimpleName() {
return simpleName;
}
public Class<? super T> getSuperclass() {
if (isClassMetadataEnabled()) {
return superclass;
} else {
return null;
}
}
public boolean isArray() {
return (modifiers & ARRAY) != 0;
}
public boolean isEnum() {
return (modifiers & ENUM) != 0;
}
public boolean isInterface() {
return (modifiers & INTERFACE) != 0;
}
public boolean isPrimitive() {
return (modifiers & PRIMITIVE) != 0;
}
public String toString() {
return (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))
+ getName();
}
/**
* Used by Enum to allow getSuperclass() to be pruned.
*/
Class<? super T> getEnumSuperclass() {
return enumSuperclass;
}
}