diff --git a/artemis-gwt/pom.xml b/artemis-gwt/pom.xml
new file mode 100644
index 000000000..bd05bc41d
--- /dev/null
+++ b/artemis-gwt/pom.xml
@@ -0,0 +1,58 @@
+
+ 4.0.0
+
+ net.onedaybeard.artemis
+ artemis-parent
+ 0.5.1-SNAPSHOT
+
+ artemis-gwt
+
+
+
+
+ ${project.groupId}
+ artemis-odb
+ ${project.version}
+
+
+
+ com.google.gwt
+ gwt-user
+ 2.5.1
+
+
+
+ com.google.gwt
+ gwt-dev
+ 2.5.1
+ provided
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+ attach-sources
+ generate-resources
+
+ jar-no-fork
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/artemis-gwt/src/main/java/com/artemis/backends/artemis_backends_gwt.gwt.xml b/artemis-gwt/src/main/java/com/artemis/backends/artemis_backends_gwt.gwt.xml
new file mode 100644
index 000000000..fbc16b72e
--- /dev/null
+++ b/artemis-gwt/src/main/java/com/artemis/backends/artemis_backends_gwt.gwt.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/artemis-gwt/src/main/java/com/artemis/backends/gwt/emu/com/artemis/utils/reflect/ArrayReflection.java b/artemis-gwt/src/main/java/com/artemis/backends/gwt/emu/com/artemis/utils/reflect/ArrayReflection.java
new file mode 100644
index 000000000..eef6082c4
--- /dev/null
+++ b/artemis-gwt/src/main/java/com/artemis/backends/gwt/emu/com/artemis/utils/reflect/ArrayReflection.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright 2011 See AUTHORS file.
+ *
+ * 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 com.artemis.utils.reflect;
+
+import com.artemis.gwtref.client.ReflectionCache;
+
+/** Utilities for Array reflection.
+ * @author nexsoftware */
+public final class ArrayReflection {
+
+ /** Creates a new array with the specified component type and length. */
+ static public Object newInstance (Class c, int size) {
+ return ReflectionCache.instance.newArray(c, size);
+ }
+
+ /** Returns the length of the supplied array. */
+ static public int getLength (Object array) {
+ return ReflectionCache.instance.getArrayLength(ReflectionCache.getType(array.getClass()), array);
+ }
+
+ /** Returns the value of the indexed component in the supplied array. */
+ static public Object get (Object array, int index) {
+ return ReflectionCache.instance.getArrayElement(ReflectionCache.getType(array.getClass()), array, index);
+ }
+
+ /** Sets the value of the indexed component in the supplied array to the supplied value. */
+ static public void set (Object array, int index, Object value) {
+ ReflectionCache.instance.setArrayElement(ReflectionCache.getType(array.getClass()), array, index, value);
+ }
+}
\ No newline at end of file
diff --git a/artemis-gwt/src/main/java/com/artemis/backends/gwt/emu/com/artemis/utils/reflect/ClassReflection.java b/artemis-gwt/src/main/java/com/artemis/backends/gwt/emu/com/artemis/utils/reflect/ClassReflection.java
new file mode 100644
index 000000000..261da392e
--- /dev/null
+++ b/artemis-gwt/src/main/java/com/artemis/backends/gwt/emu/com/artemis/utils/reflect/ClassReflection.java
@@ -0,0 +1,188 @@
+/*******************************************************************************
+ * Copyright 2011 See AUTHORS file.
+ *
+ * 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 com.artemis.utils.reflect;
+
+import com.artemis.gwtref.client.ReflectionCache;
+import com.artemis.gwtref.client.Type;
+import com.artemis.utils.reflect.ReflectionException;
+
+/** Utilities for Class reflection.
+ * @author nexsoftware */
+public final class ClassReflection {
+
+ /** Returns the Class object associated with the class or interface with the supplied string name. */
+ static public Class forName (String name) throws ReflectionException {
+ try {
+ return ReflectionCache.forName(name).getClassOfType();
+ } catch (ClassNotFoundException e) {
+ throw new ReflectionException("Class not found: " + name);
+ }
+ }
+
+ /** Returns the simple name of the underlying class as supplied in the source code. */
+ static public String getSimpleName (Class c) {
+ return c.getName();
+ }
+
+ /** Determines if the supplied Object is assignment-compatible with the object represented by supplied Class. */
+ static public boolean isInstance (Class c, Object obj) {
+ return isAssignableFrom(c, obj.getClass());
+ }
+
+ /** Determines if the class or interface represented by first Class parameter is either the same as, or is a superclass or
+ * superinterface of, the class or interface represented by the second Class parameter. */
+ static public boolean isAssignableFrom (Class c1, Class c2) {
+ Type c1Type = ReflectionCache.getType(c1);
+ Type c2Type = ReflectionCache.getType(c2);
+ return c1Type.isAssignableFrom(c2Type);
+ }
+
+ /** Returns true if the class or interface represented by the supplied Class is a member class. */
+ static public boolean isMemberClass (Class c) {
+ return ReflectionCache.getType(c).isMemberClass();
+ }
+
+ /** Returns true if the class or interface represented by the supplied Class is a static class. */
+ static public boolean isStaticClass (Class c) {
+ return ReflectionCache.getType(c).isStatic();
+ }
+
+ /** Creates a new instance of the class represented by the supplied Class. */
+ static public T newInstance (Class c) throws ReflectionException {
+ try {
+ return (T)ReflectionCache.getType(c).newInstance();
+ } catch (NoSuchMethodException e) {
+ throw new ReflectionException("Could not use default constructor of " + c.getName(), e);
+ }
+ }
+
+ /** Returns an array of {@link Constructor} containing the public constructors of the class represented by the supplied Class. */
+ static public Constructor[] getConstructors (Class c) {
+ com.artemis.gwtref.client.Constructor[] constructors = ReflectionCache.getType(c).getConstructors();
+ Constructor[] result = new Constructor[constructors.length];
+ for (int i = 0, j = constructors.length; i < j; i++) {
+ result[i] = new Constructor(constructors[i]);
+ }
+ return result;
+ }
+
+ /** Returns a {@link Constructor} that represents the public constructor for the supplied class which takes the supplied
+ * parameter types. */
+ static public Constructor getConstructor (Class c, Class... parameterTypes) throws ReflectionException {
+ try {
+ return new Constructor(ReflectionCache.getType(c).getConstructor(parameterTypes));
+ } catch (SecurityException e) {
+ throw new ReflectionException("Security violation while getting constructor for class: " + c.getName(), e);
+ } catch (NoSuchMethodException e) {
+ throw new ReflectionException("Constructor not found for class: " + c.getName(), e);
+ }
+ }
+
+ /** Returns a {@link Constructor} that represents the constructor for the supplied class which takes the supplied parameter
+ * types. */
+ static public Constructor getDeclaredConstructor (Class c, Class... parameterTypes) throws ReflectionException {
+ try {
+ return new Constructor(ReflectionCache.getType(c).getDeclaredConstructor(parameterTypes));
+ } catch (SecurityException e) {
+ throw new ReflectionException("Security violation while getting constructor for class: " + c.getName(), e);
+ } catch (NoSuchMethodException e) {
+ throw new ReflectionException("Constructor not found for class: " + c.getName(), e);
+ }
+ }
+
+ /** Returns an array of {@link Method} containing the public member methods of the class represented by the supplied Class. */
+ static public Method[] getMethods (Class c) {
+ com.artemis.gwtref.client.Method[] methods = ReflectionCache.getType(c).getMethods();
+ Method[] result = new Method[methods.length];
+ for (int i = 0, j = methods.length; i < j; i++) {
+ result[i] = new Method(methods[i]);
+ }
+ return result;
+ }
+
+ /** Returns a {@link Method} that represents the public member method for the supplied class which takes the supplied parameter
+ * types. */
+ static public Method getMethod (Class c, String name, Class... parameterTypes) throws ReflectionException {
+ try {
+ return new Method(ReflectionCache.getType(c).getMethod(name, parameterTypes));
+ } catch (SecurityException e) {
+ throw new ReflectionException("Security violation while getting method: " + name + ", for class: " + c.getName(), e);
+ } catch (NoSuchMethodException e) {
+ throw new ReflectionException("Method not found: " + name + ", for class: " + c.getName(), e);
+ }
+ }
+
+ /** Returns an array of {@link Method} containing the methods declared by the class represented by the supplied Class. */
+ static public Method[] getDeclaredMethods (Class c) {
+ com.artemis.gwtref.client.Method[] methods = ReflectionCache.getType(c).getDeclaredMethods();
+ Method[] result = new Method[methods.length];
+ for (int i = 0, j = methods.length; i < j; i++) {
+ result[i] = new Method(methods[i]);
+ }
+ return result;
+ }
+
+ /** Returns a {@link Method} that represents the method declared by the supplied class which takes the supplied parameter types. */
+ static public Method getDeclaredMethod (Class c, String name, Class... parameterTypes) throws ReflectionException {
+ try {
+ return new Method(ReflectionCache.getType(c).getMethod(name, parameterTypes));
+ } catch (SecurityException e) {
+ throw new ReflectionException("Security violation while getting method: " + name + ", for class: " + c.getName(), e);
+ } catch (NoSuchMethodException e) {
+ throw new ReflectionException("Method not found: " + name + ", for class: " + c.getName(), e);
+ }
+ }
+
+ /** Returns an array of {@link Field} containing the public fields of the class represented by the supplied Class. */
+ static public Field[] getFields (Class c) {
+ com.artemis.gwtref.client.Field[] fields = ReflectionCache.getType(c).getFields();
+ Field[] result = new Field[fields.length];
+ for (int i = 0, j = fields.length; i < j; i++) {
+ result[i] = new Field(fields[i]);
+ }
+ return result;
+ }
+
+ /** Returns a {@link Field} that represents the specified public member field for the supplied class. */
+ static public Field getField (Class c, String name) throws ReflectionException {
+ try {
+ return new Field(ReflectionCache.getType(c).getField(name));
+ } catch (SecurityException e) {
+ throw new ReflectionException("Security violation while getting field: " + name + ", for class: " + c.getName(), e);
+ }
+ }
+
+ /** Returns an array of {@link Field} objects reflecting all the fields declared by the supplied class. */
+ static public Field[] getDeclaredFields (Class c) {
+ com.artemis.gwtref.client.Field[] fields = ReflectionCache.getType(c).getDeclaredFields();
+ Field[] result = new Field[fields.length];
+ for (int i = 0, j = fields.length; i < j; i++) {
+ result[i] = new Field(fields[i]);
+ }
+ return result;
+ }
+
+ /** Returns a {@link Field} that represents the specified declared field for the supplied class. */
+ static public Field getDeclaredField (Class c, String name) throws ReflectionException {
+ try {
+ return new Field(ReflectionCache.getType(c).getField(name));
+ } catch (SecurityException e) {
+ throw new ReflectionException("Security violation while getting field: " + name + ", for class: " + c.getName(), e);
+ }
+ }
+
+}
diff --git a/artemis-gwt/src/main/java/com/artemis/backends/gwt/emu/com/artemis/utils/reflect/Constructor.java b/artemis-gwt/src/main/java/com/artemis/backends/gwt/emu/com/artemis/utils/reflect/Constructor.java
new file mode 100644
index 000000000..c8af16736
--- /dev/null
+++ b/artemis-gwt/src/main/java/com/artemis/backends/gwt/emu/com/artemis/utils/reflect/Constructor.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright 2011 See AUTHORS file.
+ *
+ * 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 com.artemis.utils.reflect;
+
+import com.artemis.utils.reflect.ReflectionException;
+
+/** Provides information about, and access to, a single constructor for a Class.
+ * @author nexsoftware */
+public final class Constructor {
+
+ private final com.artemis.gwtref.client.Constructor constructor;
+
+ Constructor (com.artemis.gwtref.client.Constructor constructor) {
+ this.constructor = constructor;
+ }
+
+ /** Returns an array of Class objects that represent the formal parameter types, in declaration order, of the constructor. */
+ public Class[] getParameterTypes () {
+ return null;
+ }
+
+ /** Returns the Class object representing the class or interface that declares the constructor. */
+ public Class getDeclaringClass () {
+ return constructor.getEnclosingType();
+ }
+
+ public boolean isAccessible () {
+ return constructor.isPublic();
+ }
+
+ public void setAccessible (boolean accessible) {
+ // NOOP in GWT
+ }
+
+ /** Uses the constructor to create and initialize a new instance of the constructor's declaring class, with the supplied
+ * initialization parameters. */
+ public Object newInstance (Object... args) throws ReflectionException {
+ try {
+ return constructor.newInstance(args);
+ } catch (IllegalArgumentException e) {
+ throw new ReflectionException("Illegal argument(s) supplied to constructor for class: " + getDeclaringClass().getName(),
+ e);
+ }
+ }
+
+}
diff --git a/artemis-gwt/src/main/java/com/artemis/backends/gwt/emu/com/artemis/utils/reflect/Field.java b/artemis-gwt/src/main/java/com/artemis/backends/gwt/emu/com/artemis/utils/reflect/Field.java
new file mode 100644
index 000000000..58539fe0e
--- /dev/null
+++ b/artemis-gwt/src/main/java/com/artemis/backends/gwt/emu/com/artemis/utils/reflect/Field.java
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright 2011 See AUTHORS file.
+ *
+ * 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 com.artemis.utils.reflect;
+
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
+
+import com.artemis.gwtref.client.ReflectionCache;
+import com.artemis.gwtref.client.Type;
+import com.artemis.utils.reflect.ReflectionException;
+
+/** Provides information about, and access to, a single field of a class or interface.
+ * @author nexsoftware */
+public final class Field {
+
+ private final com.artemis.gwtref.client.Field field;
+
+ Field (com.artemis.gwtref.client.Field field) {
+ this.field = field;
+ }
+
+ /** Returns the name of the field. */
+ public String getName () {
+ return field.getName();
+ }
+
+ /** Returns a Class object that identifies the declared type for the field. */
+ public Class getType () {
+ return field.getType().getClassOfType();
+ }
+
+ /** Returns the Class object representing the class or interface that declares the field. */
+ public Class getDeclaringClass () {
+ return field.getEnclosingType().getClassOfType();
+ }
+
+ public boolean isAccessible () {
+ return field.isPublic();
+ }
+
+ public void setAccessible (boolean accessible) {
+ // NOOP in GWT
+ }
+
+ /** Return true if the field does not include any of the {@code private}, {@code protected}, or {@code public} modifiers. */
+ public boolean isDefaultAccess () {
+ return !isPrivate() && !isProtected() && !isPublic();
+ }
+
+ /** Return true if the field includes the {@code final} modifier. */
+ public boolean isFinal () {
+ return field.isFinal();
+ }
+
+ /** Return true if the field includes the {@code private} modifier. */
+ public boolean isPrivate () {
+ return field.isPrivate();
+ }
+
+ /** Return true if the field includes the {@code protected} modifier. */
+ public boolean isProtected () {
+ return field.isProtected();
+ }
+
+ /** Return true if the field includes the {@code public} modifier. */
+ public boolean isPublic () {
+ return field.isPublic();
+ }
+
+ /** Return true if the field includes the {@code static} modifier. */
+ public boolean isStatic () {
+ return field.isStatic();
+ }
+
+ /** Return true if the field includes the {@code transient} modifier. */
+ public boolean isTransient () {
+ return field.isTransient();
+ }
+
+ /** Return true if the field includes the {@code volatile} modifier. */
+ public boolean isVolatile () {
+ return field.isVolatile();
+ }
+
+ /** Return true if the field is a synthetic field. */
+ public boolean isSynthetic () {
+ return field.isSynthetic();
+ }
+
+ /** If the type of the field is parameterized, returns the Class object representing the parameter type at the specified index,
+ * null otherwise. */
+ public Class getElementType (int index) {
+ Type elementType = field.getElementType(index);
+ return elementType != null ? elementType.getClassOfType() : null;
+ }
+
+ /** Returns the value of the field on the supplied object. */
+ public Object get (Object obj) throws ReflectionException {
+ try {
+ return field.get(obj);
+ } catch (IllegalArgumentException e) {
+ throw new ReflectionException("Could not get " + getDeclaringClass() + "#" + getName() + ": " + e.getMessage(), e);
+ } catch (IllegalAccessException e) {
+ throw new ReflectionException("Illegal access to field " + getName() + ": " + e.getMessage(), e);
+ }
+ }
+
+ /** Sets the value of the field on the supplied object. */
+ public void set (Object obj, Object value) throws ReflectionException {
+ try {
+ field.set(obj, value);
+ } catch (IllegalArgumentException e) {
+ throw new ReflectionException("Could not set " + getDeclaringClass() + "#" + getName() + ": " + e.getMessage(), e);
+ } catch (IllegalAccessException e) {
+ throw new ReflectionException("Illegal access to field " + getName() + ": " + e.getMessage(), e);
+ }
+ }
+
+ @SuppressWarnings("rawtypes")
+ public boolean hasAnnotation(Class annotationClass) {
+ return Arrays.asList(field.getAnnotationClasses()).contains(annotationClass.getName());
+ }
+
+}
diff --git a/artemis-gwt/src/main/java/com/artemis/backends/gwt/emu/com/artemis/utils/reflect/Method.java b/artemis-gwt/src/main/java/com/artemis/backends/gwt/emu/com/artemis/utils/reflect/Method.java
new file mode 100644
index 000000000..7a72220aa
--- /dev/null
+++ b/artemis-gwt/src/main/java/com/artemis/backends/gwt/emu/com/artemis/utils/reflect/Method.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright 2011 See AUTHORS file.
+ *
+ * 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 com.artemis.utils.reflect;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
+
+import com.artemis.gwtref.client.Parameter;
+import com.artemis.utils.reflect.ReflectionException;
+
+/** Provides information about, and access to, a single method on a class or interface.
+ * @author nexsoftware */
+public final class Method {
+
+ private final com.artemis.gwtref.client.Method method;
+
+ Method (com.artemis.gwtref.client.Method method) {
+ this.method = method;
+ }
+
+ /** Returns the name of the method. */
+ public String getName () {
+ return method.getName();
+ }
+
+ /** Returns a Class object that represents the formal return type of the method. */
+ public Class getReturnType () {
+ return method.getReturnType();
+ }
+
+ /** Returns an array of Class objects that represent the formal parameter types, in declaration order, of the method. */
+ public Class[] getParameterTypes () {
+ Parameter[] parameters = method.getParameters();
+ Class[] parameterTypes = new Class[parameters.length];
+ for (int i = 0, j = parameters.length; i < j; i++) {
+ parameterTypes[i] = parameters[i].getType();
+ }
+ return parameterTypes;
+ }
+
+ /** Returns the Class object representing the class or interface that declares the method. */
+ public Class getDeclaringClass () {
+ return method.getEnclosingType();
+ }
+
+ public boolean isAccessible () {
+ return method.isPublic();
+ }
+
+ public void setAccessible (boolean accessible) {
+ // NOOP in GWT
+ }
+
+ /** Return true if the method includes the {@code abstract} modifier. */
+ public boolean isAbstract () {
+ return method.isAbstract();
+ }
+
+ /** Return true if the method does not include any of the {@code private}, {@code protected}, or {@code public} modifiers. */
+ public boolean isDefaultAccess () {
+ return !isPrivate() && !isProtected() && !isPublic();
+ }
+
+ /** Return true if the method includes the {@code final} modifier. */
+ public boolean isFinal () {
+ return method.isFinal();
+ }
+
+ /** Return true if the method includes the {@code private} modifier. */
+ public boolean isPrivate () {
+ return method.isPrivate();
+ }
+
+ /** Return true if the method includes the {@code protected} modifier. */
+ public boolean isProtected () {
+ return method.isProtected();
+ }
+
+ /** Return true if the method includes the {@code public} modifier. */
+ public boolean isPublic () {
+ return method.isPublic();
+ }
+
+ /** Return true if the method includes the {@code native} modifier. */
+ public boolean isNative () {
+ return method.isNative();
+ }
+
+ /** Return true if the method includes the {@code static} modifier. */
+ public boolean isStatic () {
+ return method.isStatic();
+ }
+
+ /** Return true if the method takes a variable number of arguments. */
+ public boolean isVarArgs () {
+ return method.isVarArgs();
+ }
+
+ /** Invokes the underlying method on the supplied object with the supplied parameters. */
+ public Object invoke (Object obj, Object... args) throws ReflectionException {
+ try {
+ return method.invoke(obj, args);
+ } catch (IllegalArgumentException e) {
+ throw new ReflectionException("Illegal argument(s) supplied to method: " + getName(), e);
+ }
+ }
+
+}
diff --git a/artemis-gwt/src/main/java/com/artemis/backends/gwt/emu/java/util/BitSet.java b/artemis-gwt/src/main/java/com/artemis/backends/gwt/emu/java/util/BitSet.java
new file mode 100644
index 000000000..d5e3c73af
--- /dev/null
+++ b/artemis-gwt/src/main/java/com/artemis/backends/gwt/emu/java/util/BitSet.java
@@ -0,0 +1,917 @@
+/*
+ * Copyright 2009 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.util;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArrayInteger;
+
+/**
+ * This implementation uses bit groups of size 32 to keep track of when bits are
+ * set to true or false. This implementation also uses the sparse nature of
+ * JavaScript arrays to speed up cases when very few bits are set in a large bit
+ * set.
+ *
+ * Since there is no speed advantage to pre-allocating array sizes in JavaScript
+ * the underlying array's length is shrunk to Sun's "logical length" whenever
+ * length() is called. This length is the index of the highest true bit, plus
+ * one, or zero if there are aren't any. This may cause the size() method to
+ * return a different size than in a true Java VM.
+ */
+public class BitSet {
+ // To speed up certain operations this class also uses the index properties
+ // of arrays as described in section 15.4 of "Standard ECMA-262" (June
+ // 1997),
+ // which can currently be found here:
+ // http://www.mozilla.org/js/language/E262.pdf
+ //
+ // 15.4 Array Objects
+ // Array objects give special treatment to a certain class of property
+ // names.
+ // A property name P (in the form of a string value) is an array index if
+ // and
+ // only if ToString(ToUint32(P)) is equal to P and ToUint32(P) is not equal
+ // to (2^32)-1.
+
+ // checks the index range
+ private static void checkIndex(int bitIndex) {
+ // we only need to test for negatives, as there is no bit index too
+ // high.
+ if (bitIndex < 0) {
+ throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
+ }
+ }
+
+ // checks to ensure indexes are not negative and not in reverse order
+ private static void checkRange(int fromIndex, int toIndex) {
+ if (fromIndex < 0) {
+ throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
+ }
+ if (toIndex < 0) {
+ throw new IndexOutOfBoundsException("toIndex < 0: " + toIndex);
+ }
+ if (fromIndex > toIndex) {
+ throw new IndexOutOfBoundsException("fromIndex: " + fromIndex
+ + " > toIndex: " + toIndex);
+ }
+ }
+
+ // converts from a bit index to a word index
+ private static int wordIndex(int bitIndex) {
+ // 32 bits per index
+ return bitIndex >>> 5;
+ }
+
+ // converts from a word index to a bit index
+ private static int bitIndex(int wordIndex) {
+ // 1 word index for every 32 bit indexes
+ return wordIndex << 5;
+ }
+
+ // gives the word offset for a bit index
+ private static int bitOffset(int bitIndex) {
+ return bitIndex & 0x1f;
+ }
+
+ //
+ // none of the following static method perform any bounds checking
+ //
+
+ // clears one bit
+ private static void clear(JsArrayInteger array, int bitIndex) {
+ int index = wordIndex(bitIndex);
+ int word = getWord(array, index);
+ if (word != 0) {
+ // mask the correct bit out
+ setWord(array, index, word & ~(1 << (bitOffset(bitIndex))));
+ }
+ }
+
+ // clones the JSArrayInteger array
+ private static native JsArrayInteger clone(JsArrayInteger array) /*-{
+ return array.slice(0);
+ }-*/;
+
+ // flips one bit
+ private static void flip(JsArrayInteger array, int bitIndex) {
+ // calculate index and offset
+ int index = wordIndex(bitIndex);
+ int offset = bitOffset(bitIndex);
+
+ // figure out if the bit is on or off
+ int word = getWord(array, index);
+ if (((word >>> offset) & 1) == 1) {
+ // if on, turn it off
+ setWord(array, index, word & ~(1 << offset));
+ } else {
+ // if off, turn it on
+ array.set(index, word | (1 << offset));
+ }
+ };
+
+ // gets one bit
+ private static boolean get(JsArrayInteger array, int bitIndex) {
+ // retrieve the bits for the given index
+ int word = getWord(array, wordIndex(bitIndex));
+
+ // shift and mask the bit out
+ return ((word >>> (bitOffset(bitIndex))) & 1) == 1;
+ }
+
+ // sets one bit to true
+ private static void set(JsArrayInteger array, int bitIndex) {
+ int index = wordIndex(bitIndex);
+ array.set(index, getWord(array, index) | (1 << (bitOffset(bitIndex))));
+ }
+
+ // sets all bits to true within the given range
+ private static void set(JsArrayInteger array, int fromIndex, int toIndex) {
+ int first = wordIndex(fromIndex);
+ int last = wordIndex(toIndex);
+ int startBit = bitOffset(fromIndex);
+ int endBit = bitOffset(toIndex);
+
+ if (first == last) {
+ // set the bits in between first and last
+ maskInWord(array, first, startBit, endBit);
+
+ } else {
+ // set the bits from fromIndex to the next 32 bit boundary
+ if (startBit != 0) {
+ maskInWord(array, first++, startBit, 32);
+ }
+
+ // set the bits from the last 32 bit boundary to the toIndex
+ if (endBit != 0) {
+ maskInWord(array, last, 0, endBit);
+ }
+
+ //
+ // set everything in between
+ //
+ for (int i = first; i < last; i++) {
+ array.set(i, 0xffffffff);
+ }
+ }
+ }
+
+ // copies a subset of the array
+ private static native JsArrayInteger slice(JsArrayInteger array,
+ int fromIndex, int toIndex) /*-{
+ return array.slice(fromIndex, toIndex);
+ }-*/;
+
+ // trims the array to the minimum size it can without losing data
+ // returns index of the last element in the array, or -1 if empty
+ private static native int trimToSize(JsArrayInteger array) /*-{
+ var length = array.length;
+ if (length === 0) {
+ return -1;
+ }
+
+ // check if the last bit is false
+ var last = length - 1;
+ if (array[last] !== undefined) {
+ return last;
+ }
+
+ // interleave property checks and linear index checks from the end
+ var biggestSeen = -1;
+ for (var property in array) {
+
+ // test the index first
+ if (--last === -1) {
+ return -1;
+ }
+ if (array[last] !== undefined) {
+ return last;
+ }
+
+ // now check the property
+ var number = property >>> 0;
+ if (String(number) == property && number !== 0xffffffff) {
+ if (number > biggestSeen) {
+ biggestSeen = number;
+ }
+ }
+
+ }
+ array.length = biggestSeen + 1
+
+ return biggestSeen;
+ }-*/;
+
+ //
+ // word methods use the literal index into the array, not the bit index
+ //
+
+ // deletes an element from the array
+ private static native void deleteWord(JsArrayInteger array, int index) /*-{
+ delete array[index];
+ }-*/;
+
+ // flips all bits stored at a certain index
+ private static void flipWord(JsArrayInteger array, int index) {
+ int word = getWord(array, index);
+ if (word == 0) {
+ array.set(index, 0xffffffff);
+ } else {
+ word = ~word;
+ setWord(array, index, word);
+ }
+ }
+
+ // flips all bits stored at a certain index within the given range
+ private static void flipMaskedWord(JsArrayInteger array, int index,
+ int from, int to) {
+ if (from == to) {
+ return;
+ }
+ // get the bits
+ int word = getWord(array, index);
+ // adjust "to" so it will shift out those bits
+ to = 32 - to;
+ // create a mask and XOR it in
+ word ^= (((0xffffffff >>> from) << from) << to) >>> to;
+ ;
+ setWord(array, index, word);
+ }
+
+ // returns all bits stored at a certain index
+ private static native int getWord(JsArrayInteger array, int index) /*-{
+ // OR converts an undefined to 0
+ return array[index] | 0;
+ }-*/;
+
+ // sets all bits to true at a certain index within the given bit range
+ private static void maskInWord(JsArrayInteger array, int index, int from,
+ int to) {
+ // shifting by 32 is the same as shifting by 0, this check prevents that
+ // from happening in addition to the obvious avoidance of extra work
+ if (from != to) {
+ // adjust "to" so it will shift out those bits
+ to = 32 - to;
+ // create a mask and OR it in
+ int value = getWord(array, index);
+ value |= ((0xffffffff >>> from) << (from + to)) >>> to;
+ array.set(index, value);
+ }
+ };
+
+ // sets all bits to false at a certain index within the given bit range
+ private static void maskOutWord(JsArrayInteger array, int index, int from,
+ int to) {
+ int word = getWord(array, index);
+ // something only happens if word has bits set
+ if (word != 0) {
+ // create a mask
+ int mask;
+ if (from != 0) {
+ mask = 0xffffffff >>> (32 - from);
+ } else {
+ mask = 0;
+ }
+ // shifting by 32 is the same as shifting by 0
+ if (to != 32) {
+ mask |= 0xffffffff << to;
+ }
+
+ // mask it out
+ word &= mask;
+ setWord(array, index, word);
+ }
+ }
+
+ private static native int nextSetWord(JsArrayInteger array, int index) /*-{
+ // interleave property checks and linear "index" checks
+ var length = array.length;
+ var localMinimum = @java.lang.Integer::MAX_VALUE;
+ for (var property in array) {
+
+ // test the index first
+ if (array[index] !== undefined) {
+ return index;
+ }
+ if (++index >= length) {
+ return -1;
+ }
+
+ // now check the property
+ var number = property >>> 0;
+ if (String(number) == property && number !== 0xffffffff) {
+ if (number >= index && number < localMinimum) {
+ localMinimum = number;
+ }
+ }
+ }
+
+ // if local minimum is what we started at, we found nothing
+ if (localMinimum === @java.lang.Integer::MAX_VALUE) {
+ return -1;
+ }
+
+ return localMinimum;
+ }-*/;
+
+ // sets all bits at a certain index to the given value
+ private static void setWord(JsArrayInteger array, int index, int value) {
+ // keep 0s out of the array
+ if (value == 0) {
+ deleteWord(array, index);
+ } else {
+ array.set(index, value);
+ }
+ }
+
+ // sets the array length
+ private static native void setLengthWords(JsArrayInteger array, int length) /*-{
+ array.length = length;
+ }-*/;
+
+ // our array of bits
+ private JsArrayInteger array;
+
+ public BitSet() {
+ // create a new array
+ array = JavaScriptObject.createArray().cast();
+ }
+
+ public BitSet(int nbits) {
+ this();
+
+ // throw an exception to be consistent
+ // but (do we want to be consistent?)
+ if (nbits < 0) {
+ throw new NegativeArraySizeException("nbits < 0: " + nbits);
+ }
+
+ // even though the array's length is loosely kept to that of Sun's
+ // "logical
+ // length," this might help in some cases where code uses size() to fill
+ // in
+ // bits after constructing a BitSet, or after having one passed in as a
+ // parameter.
+ setLengthWords(array, wordIndex(nbits + 31));
+ }
+
+ private BitSet(JsArrayInteger array) {
+ this.array = array;
+ }
+
+ public void and(BitSet set) {
+ // a & a is just a
+ if (this == set) {
+ return;
+ }
+
+ // trim the second set to avoid extra work
+ trimToSize(set.array);
+
+ // check if the length is longer than otherLength
+ int otherLength = set.array.length();
+ if (array.length() > otherLength) {
+ // shrink the array, effectively ANDing those bits to false
+ setLengthWords(array, otherLength);
+ }
+
+ // truth table
+ //
+ // case | a | b | a & b | change?
+ // 1 | false | false | false | a is already false
+ // 2 | false | true | false | a is already false
+ // 3 | true | false | false | set a to false
+ // 4 | true | true | true | a is already true
+ //
+ // we only need to change something in case 3, so iterate over set a
+ int index = 0;
+ while ((index = nextSetWord(array, index)) != -1) {
+ setWord(array, index, array.get(index) & getWord(set.array, index));
+ index++;
+ }
+ }
+
+ public void andNot(BitSet set) {
+ // a & !a is false
+ if (this == set) {
+ // all falses result in an empty BitSet
+ clear();
+ return;
+ }
+
+ // trim the second set to avoid extra work
+ trimToSize(array);
+ int length = array.length();
+
+ // truth table
+ //
+ // case | a | b | !b | a & !b | change?
+ // 1 | false | false | true | false | a is already false
+ // 2 | false | true | false | false | a is already false
+ // 3 | true | false | true | true | a is already true
+ // 4 | true | true | false | false | set a to false
+ //
+ // we only need to change something in case 4
+ // whenever b is true, a should be false, so iterate over set b
+ int index = 0;
+ while ((index = nextSetWord(set.array, index)) != -1) {
+ setWord(array, index, getWord(array, index) & ~set.array.get(index));
+ if (++index >= length) {
+ // nothing further will affect anything
+ break;
+ }
+ }
+
+ }
+
+ public native int cardinality() /*-{
+ var count = 0;
+ var array = this.@java.util.BitSet::array;
+ for (var property in array) {
+ var number = property >>> 0;
+ if (String(number) == property && number !== 0xffffffff) {
+ count += @java.lang.Integer::bitCount(I)(array[number]);
+ }
+ }
+ return count;
+ }-*/;
+
+ public void clear() {
+ // create a new array
+ array = JavaScriptObject.createArray().cast();
+ }
+
+ public void clear(int bitIndex) {
+ checkIndex(bitIndex);
+ clear(array, bitIndex);
+ }
+
+ public void clear(int fromIndex, int toIndex) {
+ checkRange(fromIndex, toIndex);
+
+ int length = length();
+ if (fromIndex >= length) {
+ // nothing to do
+ return;
+ }
+
+ // check to see if toIndex is greater than our array length
+ if (toIndex >= length) {
+ // truncate the array by setting it's length
+ int newLength = wordIndex(fromIndex + 31);
+ setLengthWords(array, newLength);
+
+ // remove the extra bits off the end
+ if ((bitIndex(newLength)) - fromIndex != 0) {
+ maskOutWord(array, newLength - 1, bitOffset(fromIndex), 32);
+ }
+
+ } else {
+ int first = wordIndex(fromIndex);
+ int last = wordIndex(toIndex);
+ int startBit = bitOffset(fromIndex);
+ int endBit = bitOffset(toIndex);
+
+ if (first == last) {
+ // clear the bits in between first and last
+ maskOutWord(array, first, startBit, endBit);
+
+ } else {
+ // clear the bits from fromIndex to the next 32 bit boundary
+ if (startBit != 0) {
+ maskOutWord(array, first++, startBit, 32);
+ }
+
+ // clear the bits from the last 32 bit boundary to the toIndex
+ if (endBit != 0) {
+ maskOutWord(array, last, 0, endBit);
+ }
+
+ //
+ // delete everything in between
+ //
+ for (int i = first; i < last; i++) {
+ deleteWord(array, i);
+ }
+ }
+ }
+ }
+
+ public Object clone() {
+ return new BitSet(clone(array));
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this != obj) {
+
+ if (!(obj instanceof BitSet)) {
+ return false;
+ }
+
+ BitSet other = (BitSet) obj;
+
+ int last = trimToSize(array);
+ if (last != trimToSize(other.array)) {
+ return false;
+ }
+
+ int index = 0;
+ while ((index = nextSetWord(array, index)) != -1) {
+ if (getWord(array, index) != getWord(other.array, index)) {
+ return false;
+ }
+ index++;
+ }
+ }
+
+ return true;
+ }
+
+ public void flip(int bitIndex) {
+ checkIndex(bitIndex);
+ flip(array, bitIndex);
+ }
+
+ public void flip(int fromIndex, int toIndex) {
+ checkRange(fromIndex, toIndex);
+
+ int length = length();
+
+ // if we are flipping bits beyond our length, we are setting them to
+ // true
+ if (fromIndex >= length) {
+ set(array, fromIndex, toIndex);
+ return;
+ }
+
+ // check to see if toIndex is greater than our array length
+ if (toIndex >= length) {
+ set(array, length, toIndex);
+ toIndex = length;
+ }
+
+ int first = wordIndex(fromIndex);
+ int last = wordIndex(toIndex);
+ int startBit = bitOffset(fromIndex);
+ int end = bitOffset(toIndex);
+
+ if (first == last) {
+ // flip the bits in between first and last
+ flipMaskedWord(array, first, startBit, end);
+
+ } else {
+ // clear the bits from fromIndex to the next 32 bit boundary
+ if (startBit != 0) {
+ flipMaskedWord(array, first++, startBit, 32);
+ }
+
+ // clear the bits from the last 32 bit boundary to the toIndex
+ if (end != 0) {
+ flipMaskedWord(array, last, 0, end);
+ }
+
+ // flip everything in between
+ for (int i = first; i < last; i++) {
+ flipWord(array, i);
+ }
+ }
+ }
+
+ public boolean get(int bitIndex) {
+ checkIndex(bitIndex);
+ return get(array, bitIndex);
+ }
+
+ public BitSet get(int fromIndex, int toIndex) {
+ checkRange(fromIndex, toIndex);
+
+ // no need to go past our length
+ int length = length();
+ if (toIndex >= length) {
+ toIndex = length();
+ }
+
+ // this is the bit shift offset for each group of bits
+ int rightShift = bitOffset(fromIndex);
+
+ if (rightShift == 0) {
+ int subFrom = wordIndex(fromIndex);
+ int subTo = wordIndex(toIndex + 31);
+ JsArrayInteger subSet = slice(array, subFrom, subTo);
+ int leftOvers = bitOffset(toIndex);
+ if (leftOvers != 0) {
+ maskOutWord(subSet, subTo - subFrom - 1, leftOvers, 32);
+ }
+ return new BitSet(subSet);
+ }
+
+ BitSet subSet = new BitSet();
+
+ int first = wordIndex(fromIndex);
+ int last = wordIndex(toIndex);
+
+ if (first == last) {
+ // number of bits to cut from the end
+ int end = 32 - (bitOffset(toIndex));
+ // raw bits
+ int word = getWord(array, first);
+ // shift out those bits
+ word = ((word << end) >>> end) >>> rightShift;
+ // set it
+ if (word != 0) {
+ subSet.set(0, word);
+ }
+
+ } else {
+ // this will hold the newly packed bits
+ int current = 0;
+
+ // this is the raw index into the sub set
+ int subIndex = 0;
+
+ // fence post, carry over initial bits
+ int word = getWord(array, first++);
+ current = word >>> rightShift;
+
+ // a left shift will be used to shift our bits to the top of
+ // "current"
+ int leftShift = 32 - rightShift;
+
+ // loop through everything in the middle
+ for (int i = first; i <= last; i++) {
+ word = getWord(array, i);
+
+ // shift out the bits from the top, OR them into current bits
+ current |= word << leftShift;
+
+ // flush it out
+ if (current != 0) {
+ subSet.array.set(subIndex, current);
+ }
+
+ // keep track of our index
+ subIndex++;
+
+ // carry over the unused bits
+ current = word >>> rightShift;
+ }
+
+ // fence post, flush out the extra bits, but don't go past the "end"
+ int end = 32 - (bitOffset(toIndex));
+ current = (current << (rightShift + end)) >>> (rightShift + end);
+ if (current != 0) {
+ subSet.array.set(subIndex, current);
+ }
+ }
+
+ return subSet;
+ }
+
+ /**
+ * This hash is different than the one described in Sun's documentation. The
+ * described hash uses 64 bit integers and that's not practical in
+ * JavaScript.
+ */
+ @Override
+ public int hashCode() {
+ // FNV constants
+ final int fnvOffset = 0x811c9dc5;
+ final int fnvPrime = 0x1000193;
+
+ // initialize
+ final int last = trimToSize(array);
+ int hash = fnvOffset ^ last;
+
+ // loop over the data
+ for (int i = 0; i <= last; i++) {
+ int value = getWord(array, i);
+ // hash one byte at a time using FNV1
+ hash = (hash * fnvPrime) ^ (value & 0xff);
+ hash = (hash * fnvPrime) ^ ((value >>> 8) & 0xff);
+ hash = (hash * fnvPrime) ^ ((value >>> 16) & 0xff);
+ hash = (hash * fnvPrime) ^ (value >>> 24);
+ }
+
+ return hash;
+ }
+
+ public boolean intersects(BitSet set) {
+ int last = trimToSize(array);
+
+ if (this == set) {
+ // if it has any bits then it intersects itself
+ return last != -1;
+ }
+
+ int length = set.array.length();
+ int index = 0;
+ while ((index = nextSetWord(array, index)) != -1) {
+ if ((array.get(index) & getWord(set.array, index)) != 0) {
+ return true;
+ }
+ if (++index >= length) {
+ // nothing further can intersect
+ break;
+ }
+ }
+
+ return false;
+ }
+
+ public boolean isEmpty() {
+ return length() == 0;
+ }
+
+ public int length() {
+ int last = trimToSize(array);
+ if (last == -1) {
+ return 0;
+ }
+
+ // compute the position of the leftmost bit's index
+ int offsets[] = { 16, 8, 4, 2, 1 };
+ int bitMasks[] = { 0xffff0000, 0xff00, 0xf0, 0xc, 0x2 };
+ int position = bitIndex(last) + 1;
+ int word = getWord(array, last);
+ for (int i = 0; i < offsets.length; i++) {
+ if ((word & bitMasks[i]) != 0) {
+ word >>>= offsets[i];
+ position += offsets[i];
+ }
+ }
+ return position;
+ }
+
+ public int nextClearBit(int fromIndex) {
+ checkIndex(fromIndex);
+ int index = wordIndex(fromIndex);
+
+ // special case for first index
+ int fromBit = fromIndex - (bitIndex(index));
+ int word = getWord(array, index);
+ for (int i = fromBit; i < 32; i++) {
+ if ((word & (1 << i)) == 0) {
+ return (bitIndex(index)) + i;
+ }
+ }
+
+ // loop through the rest
+ while (true) {
+ index++;
+ word = getWord(array, index);
+ if (word != 0xffffffff) {
+ return (bitIndex(index)) + Integer.numberOfTrailingZeros(~word);
+ }
+ }
+ }
+
+ public int nextSetBit(int fromIndex) {
+ checkIndex(fromIndex);
+
+ int index = wordIndex(fromIndex);
+
+ // check the current word
+ int word = getWord(array, index);
+ if (word != 0) {
+ for (int i = bitOffset(fromIndex); i < 32; i++) {
+ if ((word & (1 << i)) != 0) {
+ return (bitIndex(index)) + i;
+ }
+ }
+ }
+ index++;
+
+ // find the next set word
+ trimToSize(array);
+ index = nextSetWord(array, index);
+ if (index == -1) {
+ return -1;
+ }
+
+ // return the next set bit
+ return (bitIndex(index))
+ + Integer.numberOfTrailingZeros(array.get(index));
+ };
+
+ public void or(BitSet set) {
+ // a | a is just a
+ if (this == set) {
+ return;
+ }
+
+ // truth table
+ //
+ // case | a | b | a | b | change?
+ // 1 | false | false | false | a is already false
+ // 2 | false | true | true | set a to true
+ // 3 | true | false | true | a is already true
+ // 4 | true | true | true | a is already true
+ //
+ // we only need to change something in case 2
+ // case 2 only happens when b is true, so iterate over set b
+ int index = 0;
+ while ((index = nextSetWord(set.array, index)) != -1) {
+ setWord(array, index, getWord(array, index) | set.array.get(index));
+ index++;
+ }
+ }
+
+ public void set(int bitIndex) {
+ checkIndex(bitIndex);
+ set(array, bitIndex);
+ }
+
+ public void set(int bitIndex, boolean value) {
+ if (value == true) {
+ set(bitIndex);
+ } else {
+ clear(bitIndex);
+ }
+ }
+
+ public void set(int fromIndex, int toIndex) {
+ checkRange(fromIndex, toIndex);
+ set(array, fromIndex, toIndex);
+ }
+
+ public void set(int fromIndex, int toIndex, boolean value) {
+ if (value == true) {
+ set(fromIndex, toIndex);
+ } else {
+ clear(fromIndex, toIndex);
+ }
+ }
+
+ public int size() {
+ // the number of bytes that can fit without using "more" memory
+ return bitIndex(array.length());
+ }
+
+ @Override
+ public String toString() {
+ // possibly faster if done in JavaScript and all numerical properties
+ // are
+ // put into an array and sorted
+
+ int length = length();
+ if (length == 0) {
+ // a "length" of 0 means there are no bits set to true
+ return "{}";
+ }
+
+ StringBuilder sb = new StringBuilder("{");
+
+ // at this point, there is at least one true bit, nextSetBit can not
+ // fail
+ int next = nextSetBit(0);
+ sb.append(next);
+
+ // loop until nextSetBit returns -1
+ while ((next = nextSetBit(next + 1)) != -1) {
+ sb.append(", ");
+ sb.append(next);
+ }
+
+ sb.append("}");
+ return sb.toString();
+ }
+
+ public void xor(BitSet set) {
+ // a ^ a is false
+ if (this == set) {
+ // this results in an empty BitSet
+ clear();
+ return;
+ }
+
+ // truth table
+ //
+ // case | a | b | a ^ b | change?
+ // 1 | false | false | false | a is already false
+ // 2 | false | true | true | set a to true
+ // 3 | true | false | true | a is already true
+ // 4 | true | true | false | set a to false
+ //
+ // we need to change something in cases 2 and 4
+ // cases 2 and 4 only happen when b is true, so iterate over set b
+ int index = 0;
+ while ((index = nextSetWord(set.array, index)) != -1) {
+ setWord(array, index, getWord(array, index) ^ set.array.get(index));
+ index++;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/artemis-gwt/src/main/java/com/artemis/backends/gwt/emu/java/util/UUID.java b/artemis-gwt/src/main/java/com/artemis/backends/gwt/emu/java/util/UUID.java
new file mode 100644
index 000000000..13ba03a42
--- /dev/null
+++ b/artemis-gwt/src/main/java/com/artemis/backends/gwt/emu/java/util/UUID.java
@@ -0,0 +1,112 @@
+package java.util;
+
+import java.io.Serializable;
+
+
+/**
+ * @author senk.christian@gmail.com
+ *
+ */
+public class UUID implements Serializable, Comparable {
+
+ private static final long serialVersionUID = 7373345728974414241L;
+ private static final char[] CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();
+
+ private String value;
+
+ /**
+ *
+ */
+ private UUID() {}
+
+ /**
+ * @param uuidString
+ * @return
+ */
+ public static UUID fromString(String uuidString) {
+ //TODO: Validation
+
+ final UUID uuid = new UUID();
+ uuid.value = uuidString;
+
+ return uuid;
+ }
+
+ /**
+ * @return
+ */
+ public static UUID randomUUID() {
+ return fromString(generateUUIDString());
+ }
+
+ /**
+ * Generate a RFC4122, version 4 ID. Example:
+ * "92329D39-6F5C-4520-ABFC-AAB64544E172"
+ */
+ private static String generateUUIDString() {
+ char[] uuid = new char[36];
+ int r;
+
+ // rfc4122 requires these characters
+ uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
+ uuid[14] = '4';
+
+ // Fill in random data. At i==19 set the high bits of clock sequence as
+ // per rfc4122, sec. 4.1.5
+ for (int i = 0; i < 36; i++) {
+ if (uuid[i] == 0) {
+ r = (int) (Math.random()*16);
+ uuid[i] = CHARS[(i == 19) ? (r & 0x3) | 0x8 : r & 0xf];
+ }
+ }
+ return new String(uuid);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ @Override
+ public int compareTo(UUID arg0) {
+ return value.compareTo(arg0.value);
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((value == null) ? 0 : value.hashCode());
+ return result;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ UUID other = (UUID) obj;
+ if (value == null) {
+ if (other.value != null)
+ return false;
+ } else if (!value.equals(other.value))
+ return false;
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return value;
+ }
+
+}
\ No newline at end of file
diff --git a/artemis-gwt/src/main/java/com/artemis/gwtref/ArtemisReflect.gwt.xml b/artemis-gwt/src/main/java/com/artemis/gwtref/ArtemisReflect.gwt.xml
new file mode 100644
index 000000000..bed06a5cc
--- /dev/null
+++ b/artemis-gwt/src/main/java/com/artemis/gwtref/ArtemisReflect.gwt.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/artemis-gwt/src/main/java/com/artemis/gwtref/client/Constructor.java b/artemis-gwt/src/main/java/com/artemis/gwtref/client/Constructor.java
new file mode 100644
index 000000000..a68cd60f2
--- /dev/null
+++ b/artemis-gwt/src/main/java/com/artemis/gwtref/client/Constructor.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright 2011 See AUTHORS file.
+ *
+ * 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 com.artemis.gwtref.client;
+
+/** A constructor for the enclosing type.
+ * @author mzechner */
+public class Constructor extends Method {
+ Constructor (String name, Class enclosingType, Class returnType, Parameter[] parameters, boolean isAbstract, boolean isFinal,
+ boolean isStatic, boolean isDefaultAccess, boolean isPrivate, boolean isProtected, boolean isPublic, boolean isNative,
+ boolean isVarArgs, boolean isMethod, boolean isConstructor, int methodId) {
+ super(name, enclosingType, returnType, parameters, isAbstract, isFinal, isStatic, isDefaultAccess, isPrivate, isProtected,
+ isPublic, isNative, isVarArgs, isMethod, isConstructor, methodId);
+ }
+
+ /** @return a new instance of the enclosing type of this constructor. */
+ public Object newInstance (Object... params) {
+ return super.invoke(null, params);
+ }
+}
diff --git a/artemis-gwt/src/main/java/com/artemis/gwtref/client/Field.java b/artemis-gwt/src/main/java/com/artemis/gwtref/client/Field.java
new file mode 100644
index 000000000..e5ea3bde8
--- /dev/null
+++ b/artemis-gwt/src/main/java/com/artemis/gwtref/client/Field.java
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * Copyright 2011 See AUTHORS file.
+ *
+ * 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 com.artemis.gwtref.client;
+
+import java.util.Arrays;
+
+public class Field {
+ final String name;
+ final Class enclosingType;
+ final Class type;
+ final boolean isFinal;
+ final boolean isDefaultAccess;
+ final boolean isPrivate;
+ final boolean isProtected;
+ final boolean isPublic;
+ final boolean isStatic;
+ final boolean isTransient;
+ final boolean isVolatile;
+ final int getter;
+ final int setter;
+ final Class[] elementTypes;
+ final String[] annotationClasses;
+
+ Field (String name, Class enclosingType, Class type, boolean isFinal, boolean isDefaultAccess, boolean isPrivate,
+ boolean isProtected, boolean isPublic, boolean isStatic, boolean isTransient, boolean isVolatile, int getter, int setter,
+ Class[] elementTypes, String[] annotationClasses) {
+ this.name = name;
+ this.enclosingType = enclosingType;
+ this.type = type;
+ this.isFinal = isFinal;
+ this.isDefaultAccess = isDefaultAccess;
+ this.isPrivate = isPrivate;
+ this.isProtected = isProtected;
+ this.isPublic = isPublic;
+ this.isStatic = isStatic;
+ this.isTransient = isTransient;
+ this.isVolatile = isVolatile;
+ this.getter = getter;
+ this.setter = setter;
+ this.elementTypes = elementTypes;
+ this.annotationClasses = annotationClasses;
+ }
+
+ public String[] getAnnotationClasses() {
+ return annotationClasses;
+ }
+
+ public Object get (Object obj) throws IllegalAccessException {
+ return ReflectionCache.instance.get(this, obj);
+ }
+
+ public void set (Object obj, Object value) throws IllegalAccessException {
+ ReflectionCache.instance.set(this, obj, value);
+ }
+
+ public Type getElementType (int index) {
+ if (elementTypes != null && index < elementTypes.length) return ReflectionCache.getType(elementTypes[index]);
+ return null;
+ }
+
+ public String getName () {
+ return name;
+ }
+
+ public Type getEnclosingType () {
+ return ReflectionCache.getType(enclosingType);
+ }
+
+ public Type getType () {
+ return ReflectionCache.getType(type);
+ }
+
+ public boolean isSynthetic () {
+ return false;
+ }
+
+ public boolean isFinal () {
+ return isFinal;
+ }
+
+ public boolean isDefaultAccess () {
+ return isDefaultAccess;
+ }
+
+ public boolean isPrivate () {
+ return isPrivate;
+ }
+
+ public boolean isProtected () {
+ return isProtected;
+ }
+
+ public boolean isPublic () {
+ return isPublic;
+ }
+
+ public boolean isStatic () {
+ return isStatic;
+ }
+
+ public boolean isTransient () {
+ return isTransient;
+ }
+
+ public boolean isVolatile () {
+ return isVolatile;
+ }
+
+ @Override
+ public String toString () {
+ return "Field [name=" + name + ", enclosingType=" + enclosingType + ", type=" + type + ", isFinal=" + isFinal
+ + ", isDefaultAccess=" + isDefaultAccess + ", isPrivate=" + isPrivate + ", isProtected=" + isProtected + ", isPublic="
+ + isPublic + ", isStatic=" + isStatic + ", isTransient=" + isTransient + ", isVolatile=" + isVolatile + ", getter="
+ + getter + ", setter=" + setter + ", elementTypes=" + Arrays.toString(elementTypes) + "]";
+ }
+}
diff --git a/artemis-gwt/src/main/java/com/artemis/gwtref/client/IReflectionCache.java b/artemis-gwt/src/main/java/com/artemis/gwtref/client/IReflectionCache.java
new file mode 100644
index 000000000..a065e4730
--- /dev/null
+++ b/artemis-gwt/src/main/java/com/artemis/gwtref/client/IReflectionCache.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright 2011 See AUTHORS file.
+ *
+ * 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 com.artemis.gwtref.client;
+
+import java.util.Collection;
+
+public interface IReflectionCache {
+ // Class level methods
+ public Collection getKnownTypes ();
+
+ public Type forName (String name);
+
+ public Object newArray (Class componentType, int size);
+
+ public int getArrayLength (Type type, Object obj);
+
+ public Object getArrayElement (Type type, Object obj, int i);
+
+ public void setArrayElement (Type type, Object obj, int i, Object value);
+
+ // Field Methods
+ public Object get (Field field, Object obj) throws IllegalAccessException;
+
+ public void set (Field field, Object obj, Object value) throws IllegalAccessException;
+
+ // Method Methods :p
+ public Object invoke (Method m, Object obj, Object[] params);
+}
diff --git a/artemis-gwt/src/main/java/com/artemis/gwtref/client/Method.java b/artemis-gwt/src/main/java/com/artemis/gwtref/client/Method.java
new file mode 100644
index 000000000..450dfee18
--- /dev/null
+++ b/artemis-gwt/src/main/java/com/artemis/gwtref/client/Method.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * Copyright 2011 See AUTHORS file.
+ *
+ * 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 com.artemis.gwtref.client;
+
+import java.util.Arrays;
+
+/** Describes a method of a {@link Type}.
+ * @author mzechner */
+public class Method {
+ private static final Parameter[] EMPTY_PARAMS = new Parameter[0];
+ final String name;
+ final Class enclosingType;
+ final Class returnType;
+ final boolean isAbstract;
+ final boolean isFinal;
+ final boolean isStatic;
+ final boolean isNative;
+ final boolean isDefaultAccess;
+ final boolean isPrivate;
+ final boolean isProtected;
+ final boolean isPublic;
+ final boolean isVarArgs;
+ final boolean isMethod;
+ final boolean isConstructor;
+ final Parameter[] parameters;
+ final int methodId;
+
+ public Method (String name, Class enclosingType, Class returnType, Parameter[] parameters, boolean isAbstract,
+ boolean isFinal, boolean isStatic, boolean isDefaultAccess, boolean isPrivate, boolean isProtected, boolean isPublic,
+ boolean isNative, boolean isVarArgs, boolean isMethod, boolean isConstructor, int methodId) {
+ this.name = name;
+ this.enclosingType = enclosingType;
+ this.parameters = parameters != null ? parameters : EMPTY_PARAMS;
+ this.returnType = returnType;
+ this.isAbstract = isAbstract;
+ this.isFinal = isFinal;
+ this.isStatic = isStatic;
+ this.isNative = isNative;
+ this.isDefaultAccess = isDefaultAccess;
+ this.isPrivate = isPrivate;
+ this.isProtected = isProtected;
+ this.isPublic = isPublic;
+ this.isVarArgs = isVarArgs;
+ this.isMethod = isMethod;
+ this.isConstructor = isConstructor;
+ this.methodId = methodId;
+ }
+
+ /** @return the {@link Class} of the enclosing type. */
+ public Class getEnclosingType () {
+ return enclosingType;
+ }
+
+ /** @return the {@link Class} of the return type or null. */
+ public Class getReturnType () {
+ return returnType;
+ }
+
+ /** @return the list of parameters, can be a zero size array. */
+ public Parameter[] getParameters () {
+ return parameters;
+ }
+
+ /** @return the name of the method. */
+ public String getName () {
+ return name;
+ }
+
+ public boolean isAbstract () {
+ return isAbstract;
+ }
+
+ public boolean isFinal () {
+ return isFinal;
+ }
+
+ public boolean isDefaultAccess () {
+ return isDefaultAccess;
+ }
+
+ public boolean isPrivate () {
+ return isPrivate;
+ }
+
+ public boolean isProtected () {
+ return isProtected;
+ }
+
+ public boolean isPublic () {
+ return isPublic;
+ }
+
+ public boolean isNative () {
+ return isNative;
+ }
+
+ public boolean isVarArgs () {
+ return isVarArgs;
+ }
+
+ public boolean isStatic () {
+ return isStatic;
+ }
+
+ public boolean isMethod () {
+ return isMethod;
+ }
+
+ public boolean isConstructor () {
+ return isConstructor;
+ }
+
+ /** Invokes the method on the given object. Ignores the object if this is a static method. Throws an IllegalArgumentException if
+ * the parameters do not match.
+ * @param obj the object to invoke the method on or null.
+ * @param params the parameters to pass to the method or null.
+ * @return the return value or null if the method does not return anything. */
+ public Object invoke (Object obj, Object... params) {
+ if (parameters.length != (params != null ? params.length : 0)) throw new IllegalArgumentException("Parameter mismatch");
+
+ return ReflectionCache.instance.invoke(this, obj, params);
+ }
+
+ boolean match (String name, Class... types) {
+ return this.name.equals(name) && match(types);
+ }
+
+ boolean match (Class... types) {
+ if (types == null) return parameters.length == 0;
+ if (types.length != parameters.length) return false;
+ for (int i = 0; i < types.length; i++) {
+ Type t1 = ReflectionCache.instance.forName(parameters[i].getType().getName());
+ Type t2 = ReflectionCache.instance.forName(types[i].getName());
+ if (t1 != t2 && !t1.isAssignableFrom(t2)) return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString () {
+ return "Method [name=" + name + ", enclosingType=" + enclosingType + ", returnType=" + returnType + ", isAbstract="
+ + isAbstract + ", isFinal=" + isFinal + ", isStatic=" + isStatic + ", isNative=" + isNative + ", isDefaultAccess="
+ + isDefaultAccess + ", isPrivate=" + isPrivate + ", isProtected=" + isProtected + ", isPublic=" + isPublic
+ + ", isVarArgs=" + isVarArgs + ", isMethod=" + isMethod + ", isConstructor=" + isConstructor + ", parameters="
+ + Arrays.toString(parameters) + "]";
+ }
+}
diff --git a/artemis-gwt/src/main/java/com/artemis/gwtref/client/Parameter.java b/artemis-gwt/src/main/java/com/artemis/gwtref/client/Parameter.java
new file mode 100644
index 000000000..dcdd92f1e
--- /dev/null
+++ b/artemis-gwt/src/main/java/com/artemis/gwtref/client/Parameter.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright 2011 See AUTHORS file.
+ *
+ * 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 com.artemis.gwtref.client;
+
+public class Parameter {
+ final String name;
+ final Class type;
+ final String jnsi;
+
+ Parameter (String name, Class type, String jnsi) {
+ this.name = name;
+ this.type = type;
+ this.jnsi = jnsi;
+ }
+
+ public String getName () {
+ return name;
+ }
+
+ public Class getType () {
+ return type;
+ }
+
+ public String getJnsi () {
+ return jnsi;
+ }
+
+ @Override
+ public String toString () {
+ return "Parameter [name=" + name + ", type=" + type + ", jnsi=" + jnsi + "]";
+ }
+}
diff --git a/artemis-gwt/src/main/java/com/artemis/gwtref/client/ReflectionCache.java b/artemis-gwt/src/main/java/com/artemis/gwtref/client/ReflectionCache.java
new file mode 100644
index 000000000..7da33cf27
--- /dev/null
+++ b/artemis-gwt/src/main/java/com/artemis/gwtref/client/ReflectionCache.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright 2011 See AUTHORS file.
+ *
+ * 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 com.artemis.gwtref.client;
+
+import java.util.Collection;
+
+import com.google.gwt.core.client.GWT;
+
+public class ReflectionCache {
+ public static IReflectionCache instance = GWT.create(IReflectionCache.class);
+
+ public static Type forName (String name) throws ClassNotFoundException {
+ Type type = instance.forName(convert(name));
+ if (type == null) {
+ throw new RuntimeException("Couldn't find Type for class '" + name + "'");
+ }
+ return type;
+ }
+
+ public static Type getType (Class clazz) {
+ if (clazz == null) return null;
+ Type type = instance.forName(convert(clazz.getName()));
+ if (type == null) {
+ throw new RuntimeException("Couldn't find Type for class '" + clazz.getName() + "'");
+ }
+ return type;
+ }
+
+ private static String convert (String className) {
+ if (className.startsWith("[")) {
+ int dimensions = 0;
+ char c = className.charAt(0);
+ String suffix = "";
+ while (c == '[') {
+ dimensions++;
+ suffix += "[]";
+ c = className.charAt(dimensions);
+ }
+ char t = className.charAt(dimensions);
+ switch (t) {
+ case 'Z':
+ return "boolean" + suffix;
+ case 'B':
+ return "byte" + suffix;
+ case 'C':
+ return "char" + suffix;
+ case 'L':
+ return className.substring(dimensions + 1, className.length() - 1).replace('$', '.') + suffix;
+ case 'D':
+ return "double" + suffix;
+ case 'F':
+ return "float" + suffix;
+ case 'I':
+ return "int" + suffix;
+ case 'J':
+ return "long" + suffix;
+ case 'S':
+ return "short" + suffix;
+ default:
+ throw new IllegalArgumentException("Couldn't transform '" + className + "' to qualified source name");
+ }
+ } else {
+ return className.replace('$', '.');
+ }
+ }
+
+ public static Object newArray (Class componentType, int size) {
+ return instance.newArray(componentType, size);
+ }
+
+ public static Collection getKnownTypes () {
+ return instance.getKnownTypes();
+ }
+}
diff --git a/artemis-gwt/src/main/java/com/artemis/gwtref/client/Test.java b/artemis-gwt/src/main/java/com/artemis/gwtref/client/Test.java
new file mode 100644
index 000000000..cd79b0bc2
--- /dev/null
+++ b/artemis-gwt/src/main/java/com/artemis/gwtref/client/Test.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright 2011 See AUTHORS file.
+ *
+ * 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 com.artemis.gwtref.client;
+
+import com.google.gwt.core.client.EntryPoint;
+
+public class Test implements EntryPoint {
+ public static enum Enu {
+ Winter, Summer, Bleh;
+ }
+
+ public static class A {
+ String text;
+ float numberf;
+ int numberi;
+
+ public String getText () {
+ return text;
+ }
+
+ public void setText (String text) {
+ this.text = text;
+ }
+
+ public float getNumberf () {
+ return numberf;
+ }
+
+ public void setNumberf (float numberf) {
+ this.numberf = numberf;
+ }
+
+ public int getNumberi () {
+ return numberi;
+ }
+
+ public void setNumberi (int numberi) {
+ this.numberi = numberi;
+ }
+
+ public float getSum (float a, float b) {
+ return a + b;
+ }
+ }
+
+ public static class B extends A {
+ String text = "This is a string";
+
+ public void testWithPackagePrivate (C c, int a) {
+ }
+
+ public void testWidthPrivate (A c) {
+ }
+
+ public void testVoid () {
+ }
+
+ public native void test (A c) /*-{
+ // this.@com.badlogic.gwtref.client.Test.B::testWidthPrivate(LC;)(c);
+ }-*/;
+ }
+
+ public static class C {
+ }
+
+ @Override
+ public void onModuleLoad () {
+ try {
+ Type ta = ReflectionCache.getType(A.class);
+ Type tb = ReflectionCache.getType(B.class);
+ B b = (B)tb.newInstance();
+ for (Field f : tb.getFields())
+ System.out.println(f);
+ for (Method m : tb.getMethods())
+ System.out.println(m);
+
+ tb.getDeclaredFields()[0].set(b, "Field of B");
+ ta.getDeclaredFields()[0].set(b, "Field of A");
+ System.out.println(ta.getMethod("getText").invoke(b));
+ System.out.println(ta.getMethod("getSum", float.class, float.class).invoke(b, 1, 2));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/artemis-gwt/src/main/java/com/artemis/gwtref/client/Type.java b/artemis-gwt/src/main/java/com/artemis/gwtref/client/Type.java
new file mode 100644
index 000000000..202fee5f1
--- /dev/null
+++ b/artemis-gwt/src/main/java/com/artemis/gwtref/client/Type.java
@@ -0,0 +1,246 @@
+/*******************************************************************************
+ * Copyright 2011 See AUTHORS file.
+ *
+ * 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 com.artemis.gwtref.client;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+/** Describes a type (equivalent to {@link Class}), providing methods to retrieve fields, constructors, methods and super
+ * interfaces of the type. Only types that are visible (public) can be described by this class.
+ * @author mzechner */
+public class Type {
+ private static final Field[] EMPTY_FIELDS = new Field[0];
+ private static final Method[] EMPTY_METHODS = new Method[0];
+ private static final Constructor[] EMPTY_CONSTRUCTORS = new Constructor[0];
+
+ String name;
+ int id;
+ Class clazz;
+ Class superClass;
+ Set assignables = new HashSet();
+ boolean isAbstract;
+ boolean isInterface;
+ boolean isPrimitive;
+ boolean isEnum;
+ boolean isArray;
+ boolean isMemberClass;
+ boolean isStatic;
+
+ Field[] fields = EMPTY_FIELDS;
+ Method[] methods = EMPTY_METHODS;
+ Constructor[] constructors = EMPTY_CONSTRUCTORS;
+
+ Class componentType;
+ Object[] enumConstants;
+
+ /** @return a new instance of this type created via the default constructor which must be public. */
+ public Object newInstance () throws NoSuchMethodException {
+ return getConstructor().newInstance();
+ }
+
+ /** @return the fully qualified name of this type. */
+ public String getName () {
+ return name;
+ }
+
+ /** @return the {@link Class} of this type. */
+ public Class getClassOfType () {
+ return clazz;
+ }
+
+ /** @return the super class of this type or null */
+ public Type getSuperclass () {
+ try {
+ return superClass == null ? null : ReflectionCache.forName(superClass.getName());
+ } catch (ClassNotFoundException e) {
+ return null;
+ }
+ }
+
+ /** @param otherType the other type
+ * @return whether this type is assignable to the other type. */
+ public boolean isAssignableFrom (Type otherType) {
+ return otherType.assignables.contains(getClassOfType());
+ }
+
+ /** @param name the name of the field
+ * @return the public field of this type or one of its super interfaces with the given name or null. See
+ * {@link Class#getField(String)}. */
+ public Field getField (String name) {
+ Type t = this;
+ while (t != null) {
+ Field[] declFields = t.getDeclaredFields();
+ if (declFields != null) {
+ for (Field f : declFields) {
+ if (f.isPublic && f.name.equals(name)) return f;
+ }
+ }
+ t = t.getSuperclass();
+ }
+ return null;
+ }
+
+ /** @return an array containing all the public fields of this class and its super classes. See {@link Class#getFields()}. */
+ public Field[] getFields () {
+ ArrayList allFields = new ArrayList();
+ Type t = this;
+ while (t != null) {
+ Field[] declFields = t.getDeclaredFields();
+ if (declFields != null) {
+ for (Field f : declFields) {
+ if (f.isPublic) allFields.add(f);
+ }
+ }
+ t = t.getSuperclass();
+ }
+ return allFields.toArray(new Field[allFields.size()]);
+ }
+
+ /** @return an array containing all the fields of this class, including private and protected fields. See
+ * {@link Class#getDeclaredFields()}. */
+ public Field[] getDeclaredFields () {
+ return fields;
+ }
+
+ /** @param name the name of the method
+ * @param parameterTypes the types of the parameters of the method
+ * @return the public method that matches the name and parameter types of this type or one of its super interfaces.
+ * @throws NoSuchMethodException */
+ public Method getMethod (String name, Class... parameterTypes) throws NoSuchMethodException {
+ Type t = this;
+ while (t != null) {
+ Method[] declMethods = t.getDeclaredMethods();
+ if (declMethods != null) {
+ for (Method m : declMethods) {
+ if (m.isPublic() && m.match(name, parameterTypes)) return m;
+ }
+ }
+ t = t.getSuperclass();
+ }
+ throw new NoSuchMethodException();
+ }
+
+ /** s * @return an array containing all public methods of this class and its super classes. See {@link Class#getMethods()}. */
+ public Method[] getMethods () {
+ ArrayList allMethods = new ArrayList();
+ Type t = this;
+ while (t != null) {
+ Method[] declMethods = t.getDeclaredMethods();
+ if (declMethods != null) {
+ for (Method m : declMethods) {
+ if (m.isPublic()) allMethods.add(m);
+ }
+ }
+ t = t.getSuperclass();
+ }
+ return allMethods.toArray(new Method[allMethods.size()]);
+ }
+
+ /** @return an array containing all methods of this class, including abstract, private and protected methods. See
+ * {@link Class#getDeclaredMethods()}. */
+ public Method[] getDeclaredMethods () {
+ return methods;
+ }
+
+ public Constructor[] getConstructors () {
+ return constructors;
+ }
+
+ public Constructor getDeclaredConstructor (Class... parameterTypes) throws NoSuchMethodException {
+ return getConstructor(parameterTypes);
+ }
+
+ public Constructor getConstructor (Class... parameterTypes) throws NoSuchMethodException {
+ if (constructors != null) {
+ for (Constructor c : constructors) {
+ if (c.isPublic() && c.match(parameterTypes)) return c;
+ }
+ }
+ throw new NoSuchMethodException();
+ }
+
+ public boolean isAbstract () {
+ return isAbstract;
+ }
+
+ public boolean isInterface () {
+ return isInterface;
+ }
+
+ public boolean isPrimitive () {
+ return isPrimitive;
+ }
+
+ public boolean isEnum () {
+ return isEnum;
+ }
+
+ public boolean isArray () {
+ return isArray;
+ }
+
+ public boolean isMemberClass () {
+ return isMemberClass;
+ }
+
+ public boolean isStatic () {
+ return isStatic;
+ }
+
+ /** @return the class of the components if this is an array type or null. */
+ public Class getComponentType () {
+ return componentType;
+ }
+
+ /** @param obj an array object of this type.
+ * @return the length of the given array object. */
+ public int getArrayLength (Object obj) {
+ return ReflectionCache.instance.getArrayLength(this, obj);
+ }
+
+ /** @param obj an array object of this type.
+ * @param i the index of the element to retrieve.
+ * @return the element at position i in the array. */
+ public Object getArrayElement (Object obj, int i) {
+ return ReflectionCache.instance.getArrayElement(this, obj, i);
+ }
+
+ /** Sets the element i in the array object to value.
+ * @param obj an array object of this type.
+ * @param i the index of the element to set.
+ * @param value the element value. */
+ public void setArrayElement (Object obj, int i, Object value) {
+ ReflectionCache.instance.setArrayElement(this, obj, i, value);
+ }
+
+ /** @return the enumeration constants if this type is an enumeration or null. */
+ public Object[] getEnumConstants () {
+ return enumConstants;
+ }
+
+ @Override
+ public String toString () {
+ return "Type [name=" + name + ",\n clazz=" + clazz + ",\n superClass=" + superClass + ",\n assignables=" + assignables
+ + ",\n isAbstract=" + isAbstract + ",\n isInterface=" + isInterface + ",\n isPrimitive=" + isPrimitive + ",\n isEnum="
+ + isEnum + ",\n isArray=" + isArray + ",\n isMemberClass=" + isMemberClass + ",\n isStatic=" + isStatic + ",\n fields="
+ + Arrays.toString(fields) + ",\n methods=" + Arrays.toString(methods) + ",\n constructors="
+ + Arrays.toString(constructors) + ",\n componentType=" + componentType + ",\n enumConstants="
+ + Arrays.toString(enumConstants) + "]";
+ }
+}
diff --git a/artemis-gwt/src/main/java/com/artemis/gwtref/gen/ReflectionCacheGenerator.java b/artemis-gwt/src/main/java/com/artemis/gwtref/gen/ReflectionCacheGenerator.java
new file mode 100644
index 000000000..2458772e5
--- /dev/null
+++ b/artemis-gwt/src/main/java/com/artemis/gwtref/gen/ReflectionCacheGenerator.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright 2011 See AUTHORS file.
+ *
+ * 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 com.artemis.gwtref.gen;
+
+import com.google.gwt.core.ext.Generator;
+import com.google.gwt.core.ext.GeneratorContext;
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import static com.google.gwt.core.ext.TreeLogger.*;
+
+public class ReflectionCacheGenerator extends Generator {
+ @Override
+ public String generate (TreeLogger logger, GeneratorContext context, String typeName) throws UnableToCompleteException {
+ TypeOracle oracle = context.getTypeOracle();
+ assert (oracle != null);
+ JClassType type = oracle.findType(typeName);
+ if (type == null) {
+ logger.log(ERROR, "Couldn't find type '" + typeName + "'");
+ throw new UnableToCompleteException();
+ }
+
+ if (type.isInterface() == null) {
+ logger.log(ERROR, "Type '" + typeName + "' must be an interface");
+ throw new UnableToCompleteException();
+ }
+
+ ReflectionCacheSourceCreator source = new ReflectionCacheSourceCreator(logger, context, type);
+ return source.create();
+ }
+}
diff --git a/artemis-gwt/src/main/java/com/artemis/gwtref/gen/ReflectionCacheSourceCreator.java b/artemis-gwt/src/main/java/com/artemis/gwtref/gen/ReflectionCacheSourceCreator.java
new file mode 100644
index 000000000..b400ab98d
--- /dev/null
+++ b/artemis-gwt/src/main/java/com/artemis/gwtref/gen/ReflectionCacheSourceCreator.java
@@ -0,0 +1,895 @@
+/*******************************************************************************
+ * Copyright 2011 See AUTHORS file.
+ *
+ * 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 com.artemis.gwtref.gen;
+
+import java.io.PrintWriter;
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.google.gwt.core.ext.BadPropertyValueException;
+import com.google.gwt.core.ext.ConfigurationProperty;
+import com.google.gwt.core.ext.GeneratorContext;
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.TreeLogger.Type;
+import com.google.gwt.core.ext.typeinfo.JAbstractMethod;
+import com.google.gwt.core.ext.typeinfo.JArrayType;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JConstructor;
+import com.google.gwt.core.ext.typeinfo.JEnumConstant;
+import com.google.gwt.core.ext.typeinfo.JEnumType;
+import com.google.gwt.core.ext.typeinfo.JField;
+import com.google.gwt.core.ext.typeinfo.JMethod;
+import com.google.gwt.core.ext.typeinfo.JPackage;
+import com.google.gwt.core.ext.typeinfo.JParameter;
+import com.google.gwt.core.ext.typeinfo.JParameterizedType;
+import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
+import com.google.gwt.core.ext.typeinfo.JType;
+import com.google.gwt.core.ext.typeinfo.NotFoundException;
+import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
+import com.google.gwt.user.rebind.SourceWriter;
+
+public class ReflectionCacheSourceCreator {
+ private static final List PRIMITIVE_TYPES = Collections.unmodifiableList(Arrays.asList(new String[] {"char", "int",
+ "long", "byte", "short", "float", "double", "boolean"}));
+ final TreeLogger logger;
+ final GeneratorContext context;
+ final JClassType type;
+ final String simpleName;
+ final String packageName;
+ SourceWriter sw;
+ StringBuffer source = new StringBuffer();
+ List types = new ArrayList();
+ List setterGetterStubs = new ArrayList();
+ List methodStubs = new ArrayList();
+ int nextId = 0;
+
+ class SetterGetterStub {
+ int getter;
+ int setter;
+ String name;
+ String enclosingType;
+ String type;
+ boolean isStatic;
+ boolean isFinal;
+ boolean unused;
+ }
+
+ class MethodStub {
+ String enclosingType;
+ String returnType;
+ List parameterTypes = new ArrayList();
+ String jnsi;
+ int methodId;
+ boolean isStatic;
+ boolean isAbstract;
+ boolean isFinal;
+ boolean isNative;
+ boolean isConstructor;
+ boolean isMethod;
+ String name;
+ boolean unused;
+ }
+
+ public ReflectionCacheSourceCreator (TreeLogger logger, GeneratorContext context, JClassType type) {
+ this.logger = logger;
+ this.context = context;
+ this.type = type;
+ this.packageName = type.getPackage().getName();
+ this.simpleName = type.getSimpleSourceName() + "Generated";
+ logger.log(Type.INFO, type.getQualifiedSourceName());
+ }
+
+ private int nextId () {
+ return nextId++;
+ }
+
+ public String create () {
+ ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(packageName, simpleName);
+ composer.addImplementedInterface("com.artemis.gwtref.client.IReflectionCache");
+ imports(composer);
+ PrintWriter printWriter = context.tryCreate(logger, packageName, simpleName);
+ if (printWriter == null) {
+ return packageName + "." + simpleName;
+ }
+ sw = composer.createSourceWriter(context, printWriter);
+
+ generateLookups();
+
+ getKnownTypesC();
+ forNameC();
+ newArrayC();
+
+ getArrayLengthT();
+ getArrayElementT();
+ setArrayElementT();
+
+ getF();
+ setF();
+
+ invokeM();
+
+ sw.commit(logger);
+ createProxy(type);
+ return packageName + "." + simpleName;
+ }
+
+ private void createProxy (JClassType type) {
+ ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory(type.getPackage().getName(),
+ type.getSimpleSourceName() + "Proxy");
+ PrintWriter printWriter = context.tryCreate(logger, packageName, simpleName);
+ if (printWriter == null) {
+ return;
+ }
+ SourceWriter writer = composer.createSourceWriter(context, printWriter);
+ writer.commit(logger);
+ }
+
+ private void generateLookups () {
+ p("Map types = new HashMap();");
+
+ TypeOracle typeOracle = context.getTypeOracle();
+ JPackage[] packages = typeOracle.getPackages();
+
+ // gather all types from wanted packages
+ for (JPackage p : packages) {
+ for (JClassType t : p.getTypes()) {
+ gatherTypes(t.getErasedType(), types);
+ }
+ }
+
+ gatherTypes(typeOracle.findType("java.util.List").getErasedType(), types);
+ gatherTypes(typeOracle.findType("java.util.ArrayList").getErasedType(), types);
+ gatherTypes(typeOracle.findType("java.util.HashMap").getErasedType(), types);
+ gatherTypes(typeOracle.findType("java.util.Map").getErasedType(), types);
+ gatherTypes(typeOracle.findType("java.lang.String").getErasedType(), types);
+ gatherTypes(typeOracle.findType("java.lang.Boolean").getErasedType(), types);
+ gatherTypes(typeOracle.findType("java.lang.Byte").getErasedType(), types);
+ gatherTypes(typeOracle.findType("java.lang.Long").getErasedType(), types);
+ gatherTypes(typeOracle.findType("java.lang.Character").getErasedType(), types);
+ gatherTypes(typeOracle.findType("java.lang.Short").getErasedType(), types);
+ gatherTypes(typeOracle.findType("java.lang.Integer").getErasedType(), types);
+ gatherTypes(typeOracle.findType("java.lang.Float").getErasedType(), types);
+ gatherTypes(typeOracle.findType("java.lang.CharSequence").getErasedType(), types);
+ gatherTypes(typeOracle.findType("java.lang.Double").getErasedType(), types);
+ gatherTypes(typeOracle.findType("java.lang.Object").getErasedType(), types);
+
+ // sort the types so the generated output will be stable between runs
+ Collections.sort(types, new Comparator() {
+ public int compare (JType o1, JType o2) {
+ return o1.getQualifiedSourceName().compareTo(o2.getQualifiedSourceName());
+ }
+ });
+
+ // generate Type lookup generator methods.
+ int id = 0;
+ for (JType t : types) {
+ String typeGen = createTypeGenerator(t);
+ p("private void c" + (id++) + "() {");
+ p(typeGen);
+ p("}\n");
+ }
+
+ // generate constructor that calls all the type generators
+ // that populate the map.
+ p("public " + simpleName + "() {");
+ for (int i = 0; i < id; i++) {
+ p("c" + i + "();");
+ }
+ p("}");
+
+ // sort the stubs so the generated output will be stable between runs
+ Collections.sort(setterGetterStubs, new Comparator() {
+ @Override
+ public int compare (SetterGetterStub o1, SetterGetterStub o2) {
+ return new Integer(o1.setter).compareTo(o2.setter);
+ }
+ });
+
+ // generate field setters/getters
+ for (SetterGetterStub stub : setterGetterStubs) {
+ String stubSource = generateSetterGetterStub(stub);
+ if (stubSource.equals("")) stub.unused = true;
+ p(stubSource);
+ }
+
+ // sort the stubs so the generated output will be stable between runs
+ Collections.sort(methodStubs, new Comparator() {
+ @Override
+ public int compare (MethodStub o1, MethodStub o2) {
+ return new Integer(o1.methodId).compareTo(o2.methodId);
+ }
+ });
+
+ // generate methods
+ for (MethodStub stub : methodStubs) {
+ String stubSource = generateMethodStub(stub);
+ if (stubSource.equals("")) stub.unused = true;
+ p(stubSource);
+ }
+
+ logger.log(Type.INFO, types.size() + " types reflected");
+ }
+
+ private void out (String message, int nesting) {
+ for (int i = 0; i < nesting; i++)
+ System.out.print(" ");
+ System.out.println(message);
+ }
+
+ int nesting = 0;
+
+ private void gatherTypes (JType type, List types) {
+ nesting++;
+ // came here from a type that has no super class
+ if (type == null) {
+ nesting--;
+ return;
+ }
+ // package info
+ if (type.getQualifiedSourceName().contains("-")) {
+ nesting--;
+ return;
+ }
+
+ // not visible
+ if (!isVisible(type)) {
+ nesting--;
+ return;
+ }
+
+ // filter reflection scope based on configuration in gwt xml module
+ boolean keep = false;
+ String name = type.getQualifiedSourceName();
+ try {
+ ConfigurationProperty prop;
+ keep |= !name.contains(".");
+ prop = context.getPropertyOracle().getConfigurationProperty("artemis.reflect.include");
+ for (String s : prop.getValues())
+ keep |= name.contains(s);
+ prop = context.getPropertyOracle().getConfigurationProperty("artemis.reflect.exclude");
+ for (String s : prop.getValues())
+ keep &= !name.equals(s);
+ } catch (BadPropertyValueException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ if (!keep) {
+ nesting--;
+ return;
+ }
+
+ // already visited this type
+ if (types.contains(type.getErasedType())) {
+ nesting--;
+ return;
+ }
+ types.add(type.getErasedType());
+ out(type.getErasedType().getQualifiedSourceName(), nesting);
+
+ if (type instanceof JPrimitiveType) {
+ // nothing to do for a primitive type
+ nesting--;
+ return;
+ } else {
+ // gather fields
+ JClassType c = (JClassType)type;
+ JField[] fields = c.getFields();
+ if (fields != null) {
+ for (JField field : fields) {
+ gatherTypes(field.getType().getErasedType(), types);
+ }
+ }
+
+ // gather super types & interfaces
+ gatherTypes(c.getSuperclass(), types);
+ JClassType[] interfaces = c.getImplementedInterfaces();
+ if (interfaces != null) {
+ for (JClassType i : interfaces) {
+ gatherTypes(i.getErasedType(), types);
+ }
+ }
+
+ // gather method parameter & return types
+ JMethod[] methods = c.getMethods();
+ if (methods != null) {
+ for (JMethod m : methods) {
+ gatherTypes(m.getReturnType().getErasedType(), types);
+ if (m.getParameterTypes() != null) {
+ for (JType p : m.getParameterTypes()) {
+ gatherTypes(p.getErasedType(), types);
+ }
+ }
+ }
+ }
+
+ // gather inner classes
+ JClassType[] inner = c.getNestedTypes();
+ if (inner != null) {
+ for (JClassType i : inner) {
+ gatherTypes(i.getErasedType(), types);
+ }
+ }
+ }
+ nesting--;
+ }
+
+ private String generateMethodStub (MethodStub stub) {
+ buffer.setLength(0);
+
+ if (stub.enclosingType == null) {
+ logger.log(Type.INFO, "method '" + stub.name + "' of invisible class is not invokable");
+ return "";
+ }
+
+ if (stub.enclosingType.startsWith("java") || stub.enclosingType.contains("google")) {
+ logger.log(Type.INFO, "not emitting code for accessing method " + stub.name + " in class '" + stub.enclosingType
+ + ", either in java.* or GWT related class");
+ return "";
+ }
+
+ if (stub.enclosingType.contains("[]")) {
+ logger.log(Type.INFO, "method '" + stub.name + "' of class '" + stub.enclosingType
+ + "' is not invokable because the class is an array type");
+ return "";
+ }
+
+ for (int i = 0; i < stub.parameterTypes.size(); i++) {
+ String paramType = stub.parameterTypes.get(i);
+ if (paramType == null) {
+ logger.log(Type.INFO, "method '" + stub.name + "' of class '" + stub.enclosingType
+ + "' is not invokable because one of its argument types is not visible");
+ return "";
+ } else if (paramType.startsWith("long") || paramType.contains("java.lang.Long")) {
+ logger.log(Type.INFO, "method '" + stub.name + "' of class '" + stub.enclosingType
+ + " has long parameter, prohibited in JSNI");
+ return "";
+ } else {
+ stub.parameterTypes.set(i, paramType.replace(".class", ""));
+ }
+ }
+ if (stub.returnType == null) {
+ logger.log(Type.INFO, "method '" + stub.name + "' of class '" + stub.enclosingType
+ + "' is not invokable because its return type is not visible");
+ return "";
+ }
+ if (stub.returnType.startsWith("long") || stub.returnType.contains("java.lang.Long")) {
+ logger.log(Type.INFO, "method '" + stub.name + "' of class '" + stub.enclosingType
+ + " has long return type, prohibited in JSNI");
+ return "";
+ }
+
+ stub.enclosingType = stub.enclosingType.replace(".class", "");
+ stub.returnType = stub.returnType.replace(".class", "");
+
+ if (stub.isMethod) {
+ boolean isVoid = stub.returnType.equals("void");
+ pbn("private native " + (isVoid ? "Object" : stub.returnType) + " m" + stub.methodId + "(");
+ if (!stub.isStatic) pbn(stub.enclosingType + " obj" + (stub.parameterTypes.size() > 0 ? ", " : ""));
+ int i = 0;
+ for (String paramType : stub.parameterTypes) {
+ pbn(paramType + " p" + i + (i < stub.parameterTypes.size() - 1 ? "," : ""));
+ i++;
+ }
+ pb(") /*-{");
+
+ if (!isVoid) pbn("return ");
+ if (stub.isStatic)
+ pbn("@" + stub.enclosingType + "::" + stub.name + "(" + stub.jnsi + ")(");
+ else
+ pbn("obj.@" + stub.enclosingType + "::" + stub.name + "(" + stub.jnsi + ")(");
+
+ for (i = 0; i < stub.parameterTypes.size(); i++) {
+ pbn("p" + i + (i < stub.parameterTypes.size() - 1 ? ", " : ""));
+ }
+ pb(");");
+ if (isVoid) pb("return null;");
+ pb("}-*/;");
+ } else {
+ pbn("private static " + stub.returnType + " m" + stub.methodId + "(");
+ int i = 0;
+ for (String paramType : stub.parameterTypes) {
+ pbn(paramType + " p" + i + (i < stub.parameterTypes.size() - 1 ? "," : ""));
+ i++;
+ }
+ pb(") {");
+
+ pbn("return new " + stub.returnType + "(");
+ for (i = 0; i < stub.parameterTypes.size(); i++) {
+ pbn("p" + i + (i < stub.parameterTypes.size() - 1 ? ", " : ""));
+ }
+ pb(");");
+
+ pb("}");
+ }
+
+ return buffer.toString();
+ }
+
+ private String generateSetterGetterStub (SetterGetterStub stub) {
+ buffer.setLength(0);
+ if (stub.enclosingType == null || stub.type == null) {
+ logger.log(Type.INFO, "field '" + stub.name + "' in class '" + stub.enclosingType + "' is not accessible as its type '"
+ + stub.type + "' is not public");
+ return "";
+ }
+ if (stub.enclosingType.startsWith("java") || stub.enclosingType.contains("google")) {
+ logger.log(Type.INFO, "not emitting code for accessing field " + stub.name + " in class '" + stub.enclosingType
+ + ", either in java.* or GWT related class");
+ return "";
+ }
+
+ if (stub.type.startsWith("long") || stub.type.contains("java.lang.Long")) {
+ logger.log(Type.INFO, "not emitting code for accessing field " + stub.name + " in class '" + stub.enclosingType
+ + " as its of type long which can't be used with JSNI");
+ return "";
+ }
+
+ stub.enclosingType = stub.enclosingType.replace(".class", "");
+ stub.type = stub.type.replace(".class", "");
+
+ pb("// " + stub.enclosingType + "#" + stub.name);
+ pbn("private native " + stub.type + " g" + stub.getter + "(" + stub.enclosingType + " obj) /*-{");
+ if (stub.isStatic)
+ pbn("return @" + stub.enclosingType + "::" + stub.name + ";");
+ else
+ pbn("return obj.@" + stub.enclosingType + "::" + stub.name + ";");
+ pb("}-*/;");
+
+ if (!stub.isFinal) {
+ pbn("private native void s" + stub.setter + "(" + stub.enclosingType + " obj, " + stub.type + " value) /*-{");
+ if (stub.isStatic)
+ pbn("@" + stub.enclosingType + "::" + stub.name + " = value");
+ else
+ pbn("obj.@" + stub.enclosingType + "::" + stub.name + " = value;");
+ pb("}-*/;");
+ }
+
+ return buffer.toString();
+ }
+
+ private boolean isVisible (JType type) {
+ if (type == null) return false;
+
+ if (type instanceof JClassType) {
+ if (type instanceof JArrayType) {
+ JType componentType = ((JArrayType)type).getComponentType();
+ while (componentType instanceof JArrayType) {
+ componentType = ((JArrayType)componentType).getComponentType();
+ }
+ if (componentType instanceof JClassType) {
+ return ((JClassType)componentType).isPublic();
+ }
+ } else {
+ return ((JClassType)type).isPublic();
+ }
+ }
+ return true;
+ }
+
+ private Map typeNames2typeIds = new HashMap();
+
+ private String createTypeGenerator (JType t) {
+ buffer.setLength(0);
+ String varName = "t";
+ if (t instanceof JPrimitiveType) varName = "p";
+ int id = nextId();
+ typeNames2typeIds.put(t.getErasedType().getQualifiedSourceName(), id);
+ pb("Type " + varName + " = new Type();");
+ pb(varName + ".name = \"" + t.getErasedType().getQualifiedSourceName() + "\";");
+ pb(varName + ".id = " + id + ";");
+ pb(varName + ".clazz = " + t.getErasedType().getQualifiedSourceName() + ".class;");
+ if (t instanceof JClassType) {
+ JClassType c = (JClassType)t;
+ if (isVisible(c.getSuperclass()))
+ pb(varName + ".superClass = " + c.getSuperclass().getErasedType().getQualifiedSourceName() + ".class;");
+ if (c.getFlattenedSupertypeHierarchy() != null) {
+ pb("Set " + varName + "Assignables = new HashSet();");
+ for (JType i : c.getFlattenedSupertypeHierarchy()) {
+ if (!isVisible(i)) continue;
+ pb(varName + "Assignables.add(" + i.getErasedType().getQualifiedSourceName() + ".class);");
+ }
+ pb(varName + ".assignables = " + varName + "Assignables;");
+ }
+ if (c.isInterface() != null) pb(varName + ".isInterface = true;");
+ if (c.isEnum() != null) pb(varName + ".isEnum = true;");
+ if (c.isArray() != null) pb(varName + ".isArray = true;");
+ if (c.isMemberType()) pb(varName + ".isMemberClass = true;");
+ pb(varName + ".isStatic = " + c.isStatic() + ";");
+ pb(varName + ".isAbstract = " + c.isAbstract() + ";");
+
+ if (c.getFields() != null) {
+ pb(varName + ".fields = new Field[] {");
+ for (JField f : c.getFields()) {
+ String enclosingType = getType(c);
+ String fieldType = getType(f.getType());
+ int setter = nextId();
+ int getter = nextId();
+ String elementType = getElementTypes(f);
+ Annotation[] annotations = f.getAnnotations();
+ StringBuilder annotationClasses = new StringBuilder("new String[]{");
+
+ for (int i = 0; i < annotations.length; i++) {
+ annotationClasses.append("\"").append(annotations[i].annotationType().getName()).append("\"");
+ if(i < annotations.length-1) {
+ annotationClasses.append(",");
+ }
+ }
+ annotationClasses.append("}");
+
+ pb("new Field(\"" + f.getName() + "\", " + enclosingType + ", " + fieldType + ", " + f.isFinal() + ", "
+ + f.isDefaultAccess() + ", " + f.isPrivate() + ", " + f.isProtected() + ", " + f.isPublic() + ", "
+ + f.isStatic() + ", " + f.isTransient() + ", " + f.isVolatile() + ", " + getter + ", " + setter + ", "
+ + elementType + ", " + annotationClasses.toString() + "), ");
+
+ SetterGetterStub stub = new SetterGetterStub();
+ stub.name = f.getName();
+ stub.enclosingType = enclosingType;
+ stub.type = fieldType;
+ stub.isStatic = f.isStatic();
+ stub.isFinal = f.isFinal();
+ if (enclosingType != null && fieldType != null) {
+ stub.getter = getter;
+ stub.setter = setter;
+ }
+ setterGetterStubs.add(stub);
+ }
+ pb("};");
+ }
+
+ printMethods(c, varName, "Method", c.getMethods());
+ if (!c.isAbstract() && (c.getEnclosingType() == null || c.isStatic())) {
+ printMethods(c, varName, "Constructor", c.getConstructors());
+ } else {
+ logger.log(Type.INFO, c.getName() + " can't be instantiated. Constructors not generated");
+ }
+
+ if (c.isArray() != null) {
+ pb(varName + ".componentType = " + getType(c.isArray().getComponentType()) + ";");
+ }
+ if (c.isEnum() != null) {
+ JEnumConstant[] enumConstants = c.isEnum().getEnumConstants();
+ if (enumConstants != null) {
+ pb(varName + ".enumConstants = new Object[" + enumConstants.length + "];");
+ for (int i = 0; i < enumConstants.length; i++) {
+ pb(varName + ".enumConstants[" + i + "] = " + c.getErasedType().getQualifiedSourceName() + "."
+ + enumConstants[i].getName() + ";");
+ }
+ }
+ }
+ } else {
+ pb(varName + ".isPrimitive = true;");
+ }
+
+ pb("types.put(\"" + t.getErasedType().getQualifiedSourceName() + "\", " + varName + ");");
+ return buffer.toString();
+ }
+
+ private void printMethods (JClassType c, String varName, String methodType, JAbstractMethod[] methodTypes) {
+ if (methodTypes != null) {
+ pb(varName + "." + methodType.toLowerCase() + "s = new " + methodType + "[] {");
+ for (JAbstractMethod m : methodTypes) {
+ MethodStub stub = new MethodStub();
+ stub.enclosingType = getType(c);
+ if (m.isMethod() != null) {
+ stub.isMethod = true;
+ stub.returnType = getType(m.isMethod().getReturnType());
+ stub.isStatic = m.isMethod().isStatic();
+ stub.isAbstract = m.isMethod().isAbstract();
+ stub.isNative = m.isMethod().isAbstract();
+ stub.isFinal = m.isMethod().isFinal();
+ } else {
+ stub.isConstructor = true;
+ stub.returnType = stub.enclosingType;
+ }
+ stub.jnsi = "";
+ stub.methodId = nextId();
+ stub.name = m.getName();
+ methodStubs.add(stub);
+
+ pb("new " + methodType + "(\"" + m.getName() + "\", ");
+ pb(stub.enclosingType + ", ");
+ pb(stub.returnType + ", ");
+
+ pb("new Parameter[] {");
+ if (m.getParameters() != null) {
+ for (JParameter p : m.getParameters()) {
+ stub.parameterTypes.add(getType(p.getType()));
+ stub.jnsi += p.getType().getErasedType().getJNISignature();
+ pb("new Parameter(\"" + p.getName() + "\", " + getType(p.getType()) + ", \"" + p.getType().getJNISignature()
+ + "\"), ");
+ }
+ }
+ pb("}, ");
+
+ pb(stub.isAbstract + ", " + stub.isFinal + ", " + stub.isStatic + ", " + m.isDefaultAccess() + ", " + m.isPrivate()
+ + ", " + m.isProtected() + ", " + m.isPublic() + ", " + stub.isNative + ", " + m.isVarArgs() + ", "
+ + stub.isMethod + ", " + stub.isConstructor + ", " + stub.methodId + "),");
+ }
+ pb("};");
+ }
+ }
+
+ private String getElementTypes (JField f) {
+ StringBuilder b = new StringBuilder();
+ JParameterizedType params = f.getType().isParameterized();
+ if (params != null) {
+ JClassType[] typeArgs = params.getTypeArgs();
+ b.append("new Class[] {");
+ for (JClassType typeArg : typeArgs) {
+ if (typeArg.isWildcard() != null)
+ b.append("Object.class");
+ else if (!isVisible(typeArg))
+ b.append("null");
+ else if (typeArg.isClassOrInterface() != null)
+ b.append(typeArg.isClassOrInterface().getQualifiedSourceName()).append(".class");
+ else if (typeArg.isParameterized() != null)
+ b.append(typeArg.isParameterized().getQualifiedBinaryName()).append(".class");
+ else
+ b.append("null");
+ b.append(", ");
+ }
+ b.append("}");
+ return b.toString();
+ }
+ return "null";
+ }
+
+ private String getType (JType type) {
+ if (!isVisible(type)) return null;
+ return type.getErasedType().getQualifiedSourceName() + ".class";
+ }
+
+ private void imports (ClassSourceFileComposerFactory composer) {
+ composer.addImport("java.security.AccessControlException");
+ composer.addImport("java.util.*");
+ composer.addImport("com.artemis.gwtref.client.*");
+ }
+
+ private void invokeM () {
+ p("public Object invoke(Method m, Object obj, Object[] params) {");
+ SwitchedCodeBlock pc = new SwitchedCodeBlock("m.methodId");
+ int subN = 0;
+ int nDispatch = 0;
+
+ for (MethodStub stub : methodStubs) {
+ if (stub.enclosingType == null) continue;
+ if (stub.enclosingType.contains("[]")) continue;
+ if (stub.returnType == null) continue;
+ if (stub.unused) continue;
+ boolean paramsOk = true;
+ for (String paramType : stub.parameterTypes) {
+ if (paramType == null) {
+ paramsOk = false;
+ break;
+ }
+ }
+
+ if (!paramsOk) continue;
+
+ buffer.setLength(0);
+ pbn("return m" + stub.methodId + "(");
+ addParameters(stub);
+ pbn(");");
+ pc.add(stub.methodId, buffer.toString());
+ nDispatch++;
+ if (nDispatch > 1000) {
+ pc.print();
+ pc = new SwitchedCodeBlock("m.methodId");
+ subN++;
+ p(" return invoke" + subN + "(m, obj, params);");
+ p("}");
+ p("public Object invoke" + subN + "(Method m, Object obj, Object[] params) {");
+ nDispatch = 0;
+ }
+ }
+
+ pc.print();
+ p(" throw new IllegalArgumentException(\"Missing method-stub \" + m.methodId + \" for method \" + m.name);");
+ p("}");
+ }
+
+ private void addParameters (MethodStub stub) {
+ if (!stub.isStatic && !stub.isConstructor)
+ pbn("(" + stub.enclosingType + ")obj" + (stub.parameterTypes.size() > 0 ? "," : ""));
+ for (int i = 0; i < stub.parameterTypes.size(); i++) {
+ pbn(cast(stub.parameterTypes.get(i), "params[" + i + "]") + (i < stub.parameterTypes.size() - 1 ? ", " : ""));
+ }
+ }
+
+ private String cast (String paramType, String arg) {
+ if (paramType.equals("byte") || paramType.equals("short") || paramType.equals("int") || paramType.equals("long")
+ || paramType.equals("float") || paramType.equals("double")) {
+ return "((Number)" + arg + ")." + paramType + "Value()";
+ } else if (paramType.equals("boolean")) {
+ return "((Boolean)" + arg + ")." + paramType + "Value()";
+ } else if (paramType.equals("char")) {
+ return "((Character)" + arg + ")." + paramType + "Value()";
+ } else {
+ return "((" + paramType + ")" + arg + ")";
+ }
+ }
+
+ private void setF () {
+ p("public void set(Field field, Object obj, Object value) throws IllegalAccessException {");
+ SwitchedCodeBlock pc = new SwitchedCodeBlock("field.setter");
+ for (SetterGetterStub stub : setterGetterStubs) {
+ if (stub.enclosingType == null || stub.type == null || stub.isFinal || stub.unused) continue;
+ pc.add(stub.setter, "s" + stub.setter + "(" + cast(stub.enclosingType, "obj") + ", " + cast(stub.type, "value")
+ + "); return;");
+ }
+ pc.print();
+ p(" throw new IllegalArgumentException(\"Missing setter-stub \" + field.setter + \" for field \" + field.name);");
+ p("}");
+ }
+
+ private void getF () {
+ p("public Object get(Field field, Object obj) throws IllegalAccessException {");
+ SwitchedCodeBlock pc = new SwitchedCodeBlock("field.getter");
+ for (SetterGetterStub stub : setterGetterStubs) {
+ if (stub.enclosingType == null || stub.type == null || stub.unused) continue;
+ pc.add(stub.getter, "return g" + stub.getter + "(" + cast(stub.enclosingType, "obj") + ");");
+ }
+ pc.print();
+ p(" throw new IllegalArgumentException(\"Missing getter-stub \" + field.getter + \" for field \" + field.name);");
+ p("}");
+ }
+
+ private static boolean isInstantiableWithNewOperator (JClassType t) {
+ if (!t.isDefaultInstantiable() || t instanceof JArrayType || t instanceof JEnumType) return false;
+ try {
+ JConstructor constructor = t.getConstructor(new JType[0]);
+ return constructor != null && constructor.isPublic();
+ } catch (NotFoundException e) {
+ return false;
+ }
+ }
+
+ private void setArrayElementT () {
+ p("public void setArrayElement(Type type, Object obj, int i, Object value) {");
+ SwitchedCodeBlock pc = new SwitchedCodeBlock("type.id");
+
+ for (String s : PRIMITIVE_TYPES) {
+ if (!typeNames2typeIds.containsKey(s + "[]")) continue;
+ pc.add(typeNames2typeIds.get(s + "[]"), "((" + s + "[])obj)[i] = " + cast(s, "value") + "; return;");
+ }
+
+ pc.print();
+ p(" ((Object[])obj)[i] = value;");
+ p("}");
+ }
+
+ private void getArrayElementT () {
+ p("public Object getArrayElement(Type type, Object obj, int i) {");
+ SwitchedCodeBlock pc = new SwitchedCodeBlock("type.id");
+
+ for (String s : PRIMITIVE_TYPES) {
+ if (!typeNames2typeIds.containsKey(s + "[]")) continue;
+ pc.add(typeNames2typeIds.get(s + "[]"), "return ((" + s + "[])obj)[i];");
+ }
+
+ pc.print();
+ p(" return ((Object[])obj)[i];");
+ p("}");
+ }
+
+ private void getArrayLengthT () {
+ p("public int getArrayLength(Type type, Object obj) {");
+ SwitchedCodeBlock pc = new SwitchedCodeBlock("type.id");
+
+ for (String s : PRIMITIVE_TYPES) {
+ if (!typeNames2typeIds.containsKey(s + "[]")) continue;
+ pc.add(typeNames2typeIds.get(s + "[]"), "return ((" + s + "[])obj).length;");
+ }
+
+ pc.print();
+ p(" return ((Object[])obj).length;");
+ p("}");
+ }
+
+ private void newArrayC () {
+ p("public Object newArray (Class componentType, int size) {");
+ p(" Type t = forName(componentType.getName().replace('$', '.'));");
+ p(" if (t != null) {");
+ SwitchedCodeBlock pc = new SwitchedCodeBlock("t.id");
+ for (JType type : types) {
+ if (type.getQualifiedSourceName().equals("void")) continue;
+ if (type.getQualifiedSourceName().endsWith("Void")) continue;
+ String arrayType = type.getErasedType().getQualifiedSourceName() + "[size]";
+ if (arrayType.contains("[]")) {
+ arrayType = type.getErasedType().getQualifiedSourceName();
+ arrayType = arrayType.replaceFirst("\\[\\]", "[size]") + "[]";
+ }
+ pc.add(typeNames2typeIds.get(type.getQualifiedSourceName()), "return new " + arrayType + ";");
+ }
+ pc.print();
+ p(" }");
+ p(" throw new RuntimeException(\"Couldn't create array with element type \" + componentType.getName());");
+ p("}");
+ }
+
+ private void forNameC () {
+ p("public Type forName(String name) {");
+ p(" return types.get(name);");
+ p("}");
+ }
+
+ private void getKnownTypesC () {
+ p("public Collection getKnownTypes() {");
+ p(" return types.values();");
+ p("}");
+ }
+
+ void p (String line) {
+ sw.println(line);
+ source.append(line);
+ source.append("\n");
+ }
+
+ void pn (String line) {
+ sw.print(line);
+ source.append(line);
+ }
+
+ StringBuffer buffer = new StringBuffer();
+
+ void pb (String line) {
+ buffer.append(line);
+ buffer.append("\n");
+ }
+
+ private void pbn (String line) {
+ buffer.append(line);
+ }
+
+ class SwitchedCodeBlock {
+ private List blocks = new ArrayList();
+ private final String switchStatement;
+
+ SwitchedCodeBlock (String switchStatement) {
+ this.switchStatement = switchStatement;
+ }
+
+ void add (int key, String codeBlock) {
+ KeyedCodeBlock b = new KeyedCodeBlock();
+ b.key = key;
+ b.codeBlock = codeBlock;
+ blocks.add(b);
+ }
+
+ void print () {
+ if (blocks.isEmpty()) return;
+
+ p(" switch(" + switchStatement + ") {");
+ for (KeyedCodeBlock b : blocks) {
+ p(" case " + b.key + ": " + b.codeBlock);
+ }
+ p("}");
+ }
+
+ class KeyedCodeBlock {
+ int key;
+ String codeBlock;
+ }
+ }
+}
diff --git a/artemis/pom.xml b/artemis/pom.xml
index 30a1e412c..4895c72e3 100644
--- a/artemis/pom.xml
+++ b/artemis/pom.xml
@@ -22,4 +22,22 @@
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+
+
+ attach-sources
+ generate-resources
+
+ jar-no-fork
+
+
+
+
+
+
+
diff --git a/artemis/src/main/java/com/artemis.gwt.xml b/artemis/src/main/java/com/artemis.gwt.xml
new file mode 100644
index 000000000..f8352415f
--- /dev/null
+++ b/artemis/src/main/java/com/artemis.gwt.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/artemis/src/main/java/com/artemis/BasicComponentMapper.java b/artemis/src/main/java/com/artemis/BasicComponentMapper.java
index 5ffa21a11..fc2897cc7 100644
--- a/artemis/src/main/java/com/artemis/BasicComponentMapper.java
+++ b/artemis/src/main/java/com/artemis/BasicComponentMapper.java
@@ -42,15 +42,17 @@ class BasicComponentMapper extends ComponentMapper {
}
- @Override
+ @SuppressWarnings("unchecked")
+ @Override
public A get(Entity e) throws ArrayIndexOutOfBoundsException {
- return classType.cast(components.get(e.getId()));
+ return (A) components.get(e.getId());
}
- @Override
+ @SuppressWarnings("unchecked")
+ @Override
public A getSafe(Entity e) {
if(components.isIndexWithinBounds(e.getId())) {
- return classType.cast(components.get(e.getId()));
+ return (A) components.get(e.getId());
}
return null;
}
diff --git a/artemis/src/main/java/com/artemis/ComponentManager.java b/artemis/src/main/java/com/artemis/ComponentManager.java
index 2f4a155a7..cdb99de78 100644
--- a/artemis/src/main/java/com/artemis/ComponentManager.java
+++ b/artemis/src/main/java/com/artemis/ComponentManager.java
@@ -3,6 +3,8 @@
import java.util.BitSet;
import com.artemis.utils.Bag;
+import com.artemis.utils.reflect.ClassReflection;
+import com.artemis.utils.reflect.ReflectionException;
/**
@@ -61,10 +63,8 @@ protected T create(Entity owner, Class componentClass)
case POOLED:
try {
return (T)pooledComponents.obtain((Class)componentClass);
- } catch (InstantiationException e) {
+ } catch (ReflectionException e) {
throw new InvalidComponentException(componentClass, "Unable to instantiate component.", e);
- } catch (IllegalAccessException e) {
- throw new InvalidComponentException(componentClass, "Missing public constructor.", e);
}
default:
throw new InvalidComponentException(componentClass, " unknown component type: " + type.getTaxonomy());
@@ -83,11 +83,9 @@ protected BitSet getPackedComponentOwners(ComponentType type)
private static T newInstance(Class componentClass) {
try {
- return componentClass.newInstance();
- } catch (InstantiationException e) {
+ return ClassReflection.newInstance(componentClass);
+ } catch (ReflectionException e) {
throw new InvalidComponentException(componentClass, "Unable to instantiate component.", e);
- } catch (IllegalAccessException e) {
- throw new InvalidComponentException(componentClass, "Missing public constructor.", e);
}
}
diff --git a/artemis/src/main/java/com/artemis/ComponentPool.java b/artemis/src/main/java/com/artemis/ComponentPool.java
index 70646b952..0ac3da940 100644
--- a/artemis/src/main/java/com/artemis/ComponentPool.java
+++ b/artemis/src/main/java/com/artemis/ComponentPool.java
@@ -4,6 +4,8 @@
import java.util.Map;
import com.artemis.utils.Bag;
+import com.artemis.utils.reflect.ClassReflection;
+import com.artemis.utils.reflect.ReflectionException;
class ComponentPool {
@@ -15,10 +17,10 @@ class ComponentPool {
@SuppressWarnings("unchecked")
T obtain(Class componentClass)
- throws InstantiationException, IllegalAccessException {
+ throws ReflectionException {
Pool pool = getPool(componentClass);
- return (T)((pool.size() > 0) ? pool.obtain() : componentClass.newInstance());
+ return (T)((pool.size() > 0) ? pool.obtain() : ClassReflection.newInstance(componentClass));
}
void free(PooledComponent c) {
diff --git a/artemis/src/main/java/com/artemis/ComponentType.java b/artemis/src/main/java/com/artemis/ComponentType.java
index 08c0085fb..8a039cb04 100644
--- a/artemis/src/main/java/com/artemis/ComponentType.java
+++ b/artemis/src/main/java/com/artemis/ComponentType.java
@@ -3,6 +3,7 @@
import java.util.IdentityHashMap;
import com.artemis.utils.Bag;
+import com.artemis.utils.reflect.ClassReflection;
/**
@@ -42,13 +43,13 @@ enum Taxonomy {
* @param type
* the components class
*/
- private ComponentType(Class extends Component> type) {
+ public ComponentType(Class extends Component> type) {
types.set(INDEX, this);
index = INDEX++;
this.type = type;
- if (PackedComponent.class.isAssignableFrom(type)) {
+ if (ClassReflection.isAssignableFrom(PackedComponent.class, type)) {
taxonomy = Taxonomy.PACKED;
- } else if (PooledComponent.class.isAssignableFrom(type)) {
+ } else if (ClassReflection.isAssignableFrom(PooledComponent.class, type)) {
taxonomy = Taxonomy.POOLED;
} else {
taxonomy = Taxonomy.BASIC;
@@ -66,7 +67,7 @@ public int getIndex() {
@Override
public String toString() {
- return "ComponentType["+type.getSimpleName()+"] ("+index+")";
+ return "ComponentType["+ ClassReflection.getSimpleName(type) +"] ("+index+")";
}
protected Taxonomy getTaxonomy() {
diff --git a/artemis/src/main/java/com/artemis/Entity.java b/artemis/src/main/java/com/artemis/Entity.java
index 60737ad4f..6855dd7ba 100644
--- a/artemis/src/main/java/com/artemis/Entity.java
+++ b/artemis/src/main/java/com/artemis/Entity.java
@@ -265,8 +265,9 @@ public Component getComponent(ComponentType type) {
*
* @return component that matches, or null if none is found
*/
+ @SuppressWarnings("unchecked")
public T getComponent(Class type) {
- return type.cast(getComponent(ComponentType.getTypeFor(type)));
+ return (T)getComponent(ComponentType.getTypeFor(type));
}
/**
diff --git a/artemis/src/main/java/com/artemis/InvalidComponentException.java b/artemis/src/main/java/com/artemis/InvalidComponentException.java
index 321d73ee0..5fdb2a1b3 100644
--- a/artemis/src/main/java/com/artemis/InvalidComponentException.java
+++ b/artemis/src/main/java/com/artemis/InvalidComponentException.java
@@ -1,5 +1,7 @@
package com.artemis;
+import com.artemis.utils.reflect.ClassReflection;
+
@SuppressWarnings("serial")
public class InvalidComponentException extends RuntimeException {
@@ -16,7 +18,7 @@ public InvalidComponentException(Class> componentClass, String string, Excepti
}
private static String message(Class> componentClass, String string) {
- return componentClass.getSimpleName() + ": " + string;
+ return ClassReflection.getSimpleName(componentClass) + ": " + string;
}
public Class> getComponentClass() {
diff --git a/artemis/src/main/java/com/artemis/PackedComponentMapper.java b/artemis/src/main/java/com/artemis/PackedComponentMapper.java
index e86d3df39..568000a2f 100644
--- a/artemis/src/main/java/com/artemis/PackedComponentMapper.java
+++ b/artemis/src/main/java/com/artemis/PackedComponentMapper.java
@@ -1,6 +1,8 @@
package com.artemis;
import java.util.BitSet;
+import com.artemis.utils.reflect.ClassReflection;
+import com.artemis.utils.reflect.ReflectionException;
/**
* High performance packed component retrieval from entities. Each instance
@@ -45,10 +47,11 @@ static PackedComponentMapper create(Class type
return new PackedComponentMapper(type, world);
}
- @Override @SuppressWarnings("unchecked")
+ @Override
+ @SuppressWarnings("unchecked")
public A get(Entity e) throws ArrayIndexOutOfBoundsException {
component.forEntity(e);
- return (A)component;
+ return (A) component;
}
@Override
@@ -83,11 +86,9 @@ public A getSafe(Entity e, boolean forceNewInstance) {
private A newInstance(Class type) {
try {
- return classType.newInstance();
- } catch (InstantiationException e) {
+ return (A) ClassReflection.newInstance(classType);
+ } catch (ReflectionException e) {
throw new InvalidComponentException(type, "Unable to instantiate component.", e);
- } catch (IllegalAccessException e) {
- throw new InvalidComponentException(type, "Missing public constructor or too restrictive access.", e);
}
}
}
diff --git a/artemis/src/main/java/com/artemis/World.java b/artemis/src/main/java/com/artemis/World.java
index 3b773dea2..a6d9186ef 100644
--- a/artemis/src/main/java/com/artemis/World.java
+++ b/artemis/src/main/java/com/artemis/World.java
@@ -1,7 +1,5 @@
package com.artemis;
-import java.lang.reflect.Field;
-import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
@@ -11,6 +9,8 @@
import com.artemis.annotations.Mapper;
import com.artemis.utils.Bag;
import com.artemis.utils.ImmutableBag;
+import com.artemis.utils.reflect.ClassReflection;
+import com.artemis.utils.reflect.Field;
/**
@@ -197,8 +197,9 @@ public final T setManager(T manager) {
*
* @return the manager
*/
- public T getManager(Class managerType) {
- return managerType.cast(managers.get(managerType));
+ @SuppressWarnings("unchecked")
+ public T getManager(Class managerType) {
+ return (T)managers.get(managerType);
}
/**
@@ -443,8 +444,9 @@ private void notifyManagers(Performer performer, Entity e) {
*
* @return instance of the system in this world
*/
- public T getSystem(Class type) {
- return type.cast(systems.get(type));
+ @SuppressWarnings("unchecked")
+ public T getSystem(Class type) {
+ return (T)systems.get(type);
}
/**
@@ -618,14 +620,10 @@ private static final class ComponentMapperInitHelper {
public static void config(Object target, World world) throws RuntimeException {
try {
Class> clazz = target.getClass();
- for (Field field : clazz.getDeclaredFields()) {
- Mapper annotation = field.getAnnotation(Mapper.class);
- if (annotation != null && Mapper.class.isAssignableFrom(Mapper.class)) {
- ParameterizedType genericType = (ParameterizedType) field.getGenericType();
-
+ for (Field field : ClassReflection.getDeclaredFields(clazz)) {
+ if (field.hasAnnotation(Mapper.class)) {
@SuppressWarnings("unchecked")
- Class componentType = (Class) genericType.getActualTypeArguments()[0];
-
+ Class componentType = (Class) field.getElementType(0);
field.setAccessible(true);
field.set(target, world.getMapper(componentType));
}
diff --git a/artemis/src/main/java/com/artemis/utils/FastMath.java b/artemis/src/main/java/com/artemis/utils/FastMath.java
index 36f921569..aa961df88 100644
--- a/artemis/src/main/java/com/artemis/utils/FastMath.java
+++ b/artemis/src/main/java/com/artemis/utils/FastMath.java
@@ -54,9 +54,12 @@ public final static double atan(final double x) {
}
public final static double inverseSqrt(double x) {
- final double xhalves = 0.5d * x;
- x = Double.longBitsToDouble(0x5FE6EB50C7B537AAl - (Double.doubleToRawLongBits(x) >> 1));
- return x * (1.5d - xhalves * x * x); // more iterations possible
+ double xhalf = 0.5d * x;
+ long i = Double.doubleToLongBits(x);
+ i = 0x5fe6ec85e7de30daL - (i >> 1);
+ x = Double.longBitsToDouble(i);
+ x = x * (1.5d - xhalf * x * x);
+ return x;
}
public final static double sqrt(final double x) {
diff --git a/artemis/src/main/java/com/artemis/utils/Utils.java b/artemis/src/main/java/com/artemis/utils/Utils.java
index ff07ef172..a3ce56618 100644
--- a/artemis/src/main/java/com/artemis/utils/Utils.java
+++ b/artemis/src/main/java/com/artemis/utils/Utils.java
@@ -137,33 +137,5 @@ public static boolean collides(float x1, float y1, float radius1, float x2, floa
return d < 0;
}
- public static String readFileContents(String file) {
- InputStream is = Utils.class.getClassLoader().getResourceAsStream(file);
- String contents = "";
- try {
- if (is != null) {
- Writer writer = new StringWriter();
-
- char[] buffer = new char[1024];
- Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
- int n;
- while ((n = reader.read(buffer)) != -1) {
- writer.write(buffer, 0, n);
- }
-
- contents = writer.toString();
- }
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- try {
- is.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- return contents;
- }
}
diff --git a/artemis/src/main/java/com/artemis/utils/reflect/ArrayReflection.java b/artemis/src/main/java/com/artemis/utils/reflect/ArrayReflection.java
new file mode 100644
index 000000000..028244c63
--- /dev/null
+++ b/artemis/src/main/java/com/artemis/utils/reflect/ArrayReflection.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright 2011 See AUTHORS file.
+ *
+ * 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 com.artemis.utils.reflect;
+
+/** Utilities for Array reflection.
+ * @author nexsoftware */
+public final class ArrayReflection {
+
+ /** Creates a new array with the specified component type and length. */
+ static public Object newInstance (Class c, int size) {
+ return java.lang.reflect.Array.newInstance(c, size);
+ }
+
+ /** Returns the length of the supplied array. */
+ static public int getLength (Object array) {
+ return java.lang.reflect.Array.getLength(array);
+ }
+
+ /** Returns the value of the indexed component in the supplied array. */
+ static public Object get (Object array, int index) {
+ return java.lang.reflect.Array.get(array, index);
+ }
+
+ /** Sets the value of the indexed component in the supplied array to the supplied value. */
+ static public void set (Object array, int index, Object value) {
+ java.lang.reflect.Array.set(array, index, value);
+ }
+
+}
\ No newline at end of file
diff --git a/artemis/src/main/java/com/artemis/utils/reflect/ClassReflection.java b/artemis/src/main/java/com/artemis/utils/reflect/ClassReflection.java
new file mode 100644
index 000000000..7ebe10216
--- /dev/null
+++ b/artemis/src/main/java/com/artemis/utils/reflect/ClassReflection.java
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * Copyright 2011 See AUTHORS file.
+ *
+ * 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 com.artemis.utils.reflect;
+
+import java.lang.reflect.Modifier;
+
+/** Utilities for Class reflection.
+ * @author nexsoftware */
+public final class ClassReflection {
+
+ /** Returns the Class object associated with the class or interface with the supplied string name. */
+ static public Class forName (String name) throws ReflectionException {
+ try {
+ return Class.forName(name);
+ } catch (ClassNotFoundException e) {
+ throw new ReflectionException("Class not found: " + name, e);
+ }
+ }
+
+ /** Returns the simple name of the underlying class as supplied in the source code. */
+ static public String getSimpleName (Class c) {
+ return c.getSimpleName();
+ }
+
+ /** Determines if the supplied Object is assignment-compatible with the object represented by supplied Class. */
+ static public boolean isInstance (Class c, Object obj) {
+ return c.isInstance(obj);
+ }
+
+ /** Determines if the class or interface represented by first Class parameter is either the same as, or is a superclass or
+ * superinterface of, the class or interface represented by the second Class parameter. */
+ static public boolean isAssignableFrom (Class c1, Class c2) {
+ return c1.isAssignableFrom(c2);
+ }
+
+ /** Returns true if the class or interface represented by the supplied Class is a member class. */
+ static public boolean isMemberClass (Class c) {
+ return c.isMemberClass();
+ }
+
+ /** Returns true if the class or interface represented by the supplied Class is a static class. */
+ static public boolean isStaticClass (Class c) {
+ return Modifier.isStatic(c.getModifiers());
+ }
+
+ /** Creates a new instance of the class represented by the supplied Class. */
+ static public T newInstance (Class c) throws ReflectionException {
+ try {
+ return c.newInstance();
+ } catch (InstantiationException e) {
+ throw new ReflectionException("Could not instantiate instance of class: " + c.getName(), e);
+ } catch (IllegalAccessException e) {
+ throw new ReflectionException("Could not instantiate instance of class: " + c.getName(), e);
+ }
+ }
+
+ /** Returns an array of {@link Constructor} containing the public constructors of the class represented by the supplied Class. */
+ static public Constructor[] getConstructors (Class c) {
+ java.lang.reflect.Constructor[] constructors = c.getConstructors();
+ Constructor[] result = new Constructor[constructors.length];
+ for (int i = 0, j = constructors.length; i < j; i++) {
+ result[i] = new Constructor(constructors[i]);
+ }
+ return result;
+ }
+
+ /** Returns a {@link Constructor} that represents the public constructor for the supplied class which takes the supplied parameter types. */
+ static public Constructor getConstructor (Class c, Class... parameterTypes) throws ReflectionException {
+ try {
+ return new Constructor(c.getConstructor(parameterTypes));
+ } catch (SecurityException e) {
+ throw new ReflectionException("Security violation occurred while getting constructor for class: '" + c.getName() + "'.", e);
+ } catch (NoSuchMethodException e) {
+ throw new ReflectionException("Constructor not found for class: " + c.getName(), e);
+ }
+ }
+
+ /** Returns a {@link Constructor} that represents the constructor for the supplied class which takes the supplied parameter types. */
+ static public Constructor getDeclaredConstructor (Class c, Class... parameterTypes) throws ReflectionException {
+ try {
+ return new Constructor(c.getDeclaredConstructor(parameterTypes));
+ } catch (SecurityException e) {
+ throw new ReflectionException("Security violation while getting constructor for class: " + c.getName(), e);
+ } catch (NoSuchMethodException e) {
+ throw new ReflectionException("Constructor not found for class: " + c.getName(), e);
+ }
+ }
+
+ /** Returns an array of {@link Method} containing the public member methods of the class represented by the supplied Class. */
+ static public Method[] getMethods (Class c) {
+ java.lang.reflect.Method[] methods = c.getMethods();
+ Method[] result = new Method[methods.length];
+ for (int i = 0, j = methods.length; i < j; i++) {
+ result[i] = new Method(methods[i]);
+ }
+ return result;
+ }
+
+ /** Returns a {@link Method} that represents the public member method for the supplied class which takes the supplied parameter types. */
+ static public Method getMethod (Class c, String name, Class... parameterTypes) throws ReflectionException {
+ try {
+ return new Method(c.getMethod(name, parameterTypes));
+ } catch (SecurityException e) {
+ throw new ReflectionException("Security violation while getting method: " + name + ", for class: " + c.getName(), e);
+ } catch (NoSuchMethodException e) {
+ throw new ReflectionException("Method not found: " + name + ", for class: " + c.getName(), e);
+ }
+ }
+
+ /** Returns an array of {@link Method} containing the methods declared by the class represented by the supplied Class. */
+ static public Method[] getDeclaredMethods (Class c) {
+ java.lang.reflect.Method[] methods = c.getDeclaredMethods();
+ Method[] result = new Method[methods.length];
+ for (int i = 0, j = methods.length; i < j; i++) {
+ result[i] = new Method(methods[i]);
+ }
+ return result;
+ }
+
+ /** Returns a {@link Method} that represents the method declared by the supplied class which takes the supplied parameter types. */
+ static public Method getDeclaredMethod (Class c, String name, Class... parameterTypes) throws ReflectionException {
+ try {
+ return new Method(c.getDeclaredMethod(name, parameterTypes));
+ } catch (SecurityException e) {
+ throw new ReflectionException("Security violation while getting method: " + name + ", for class: " + c.getName(), e);
+ } catch (NoSuchMethodException e) {
+ throw new ReflectionException("Method not found: " + name + ", for class: " + c.getName(), e);
+ }
+ }
+
+ /** Returns an array of {@link Field} containing the public fields of the class represented by the supplied Class. */
+ static public Field[] getFields (Class c) {
+ java.lang.reflect.Field[] fields = c.getFields();
+ Field[] result = new Field[fields.length];
+ for (int i = 0, j = fields.length; i < j; i++) {
+ result[i] = new Field(fields[i]);
+ }
+ return result;
+ }
+
+ /** Returns a {@link Field} that represents the specified public member field for the supplied class. */
+ static public Field getField (Class c, String name) throws ReflectionException {
+ try {
+ return new Field(c.getField(name));
+ } catch (SecurityException e) {
+ throw new ReflectionException("Security violation while getting field: " + name + ", for class: " + c.getName(), e);
+ } catch (NoSuchFieldException e) {
+ throw new ReflectionException("Field not found: " + name + ", for class: " + c.getName(), e);
+ }
+ }
+
+ /** Returns an array of {@link Field} objects reflecting all the fields declared by the supplied class. */
+ static public Field[] getDeclaredFields (Class c) {
+ java.lang.reflect.Field[] fields = c.getDeclaredFields();
+ Field[] result = new Field[fields.length];
+ for (int i = 0, j = fields.length; i < j; i++) {
+ result[i] = new Field(fields[i]);
+ }
+ return result;
+ }
+
+ /** Returns a {@link Field} that represents the specified declared field for the supplied class. */
+ static public Field getDeclaredField (Class c, String name) throws ReflectionException {
+ try {
+ return new Field(c.getDeclaredField(name));
+ } catch (SecurityException e) {
+ throw new ReflectionException("Security violation while getting field: " + name + ", for class: " + c.getName(), e);
+ } catch (NoSuchFieldException e) {
+ throw new ReflectionException("Field not found: " + name + ", for class: " + c.getName(), e);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/artemis/src/main/java/com/artemis/utils/reflect/Constructor.java b/artemis/src/main/java/com/artemis/utils/reflect/Constructor.java
new file mode 100644
index 000000000..a8ded6f49
--- /dev/null
+++ b/artemis/src/main/java/com/artemis/utils/reflect/Constructor.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright 2011 See AUTHORS file.
+ *
+ * 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 com.artemis.utils.reflect;
+
+import java.lang.reflect.InvocationTargetException;
+
+/** Provides information about, and access to, a single constructor for a Class.
+ * @author nexsoftware */
+public final class Constructor {
+
+ private final java.lang.reflect.Constructor constructor;
+
+ Constructor (java.lang.reflect.Constructor constructor) {
+ this.constructor = constructor;
+ }
+
+ /** Returns an array of Class objects that represent the formal parameter types, in declaration order, of the constructor. */
+ public Class[] getParameterTypes () {
+ return constructor.getParameterTypes();
+ }
+
+ /** Returns the Class object representing the class or interface that declares the constructor. */
+ public Class getDeclaringClass () {
+ return constructor.getDeclaringClass();
+ }
+
+ public boolean isAccessible () {
+ return constructor.isAccessible();
+ }
+
+ public void setAccessible (boolean accessible) {
+ constructor.setAccessible(accessible);
+ }
+
+ /** Uses the constructor to create and initialize a new instance of the constructor's declaring class, with the supplied initialization parameters. */
+ public Object newInstance (Object... args) throws ReflectionException {
+ try {
+ return constructor.newInstance(args);
+ } catch (IllegalArgumentException e) {
+ throw new ReflectionException("Illegal argument(s) supplied to constructor for class: " + getDeclaringClass().getName(), e);
+ } catch (InstantiationException e) {
+ throw new ReflectionException("Could not instantiate instance of class: " + getDeclaringClass().getName(), e);
+ } catch (IllegalAccessException e) {
+ throw new ReflectionException("Could not instantiate instance of class: " + getDeclaringClass().getName(), e);
+ } catch (InvocationTargetException e) {
+ throw new ReflectionException("Exception occurred in constructor for class: " + getDeclaringClass().getName(), e);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/artemis/src/main/java/com/artemis/utils/reflect/Field.java b/artemis/src/main/java/com/artemis/utils/reflect/Field.java
new file mode 100644
index 000000000..d0fdddee3
--- /dev/null
+++ b/artemis/src/main/java/com/artemis/utils/reflect/Field.java
@@ -0,0 +1,151 @@
+/*******************************************************************************
+ * Copyright 2011 See AUTHORS file.
+ *
+ * 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 com.artemis.utils.reflect;
+
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+
+/** Provides information about, and access to, a single field of a class or interface.
+ * @author nexsoftware */
+public final class Field {
+
+ private final java.lang.reflect.Field field;
+
+ Field (java.lang.reflect.Field field) {
+ this.field = field;
+ }
+
+ /** Returns the name of the field. */
+ public String getName () {
+ return field.getName();
+ }
+
+ /** Returns a Class object that identifies the declared type for the field. */
+ public Class getType () {
+ return field.getType();
+ }
+
+ /** Returns the Class object representing the class or interface that declares the field. */
+ public Class getDeclaringClass () {
+ return field.getDeclaringClass();
+ }
+
+ public boolean isAccessible () {
+ return field.isAccessible();
+ }
+
+ public void setAccessible (boolean accessible) {
+ field.setAccessible(accessible);
+ }
+
+ /** Return true if the field does not include any of the {@code private}, {@code protected}, or {@code public} modifiers. */
+ public boolean isDefaultAccess () {
+ return !isPrivate() && !isProtected() && !isPublic();
+ }
+
+ /** Return true if the field includes the {@code final} modifier. */
+ public boolean isFinal () {
+ return Modifier.isFinal(field.getModifiers());
+ }
+
+ /** Return true if the field includes the {@code private} modifier. */
+ public boolean isPrivate () {
+ return Modifier.isPrivate(field.getModifiers());
+ }
+
+ /** Return true if the field includes the {@code protected} modifier. */
+ public boolean isProtected () {
+ return Modifier.isProtected(field.getModifiers());
+ }
+
+ /** Return true if the field includes the {@code public} modifier. */
+ public boolean isPublic () {
+ return Modifier.isPublic(field.getModifiers());
+ }
+
+ /** Return true if the field includes the {@code static} modifier. */
+ public boolean isStatic () {
+ return Modifier.isStatic(field.getModifiers());
+ }
+
+ /** Return true if the field includes the {@code transient} modifier. */
+ public boolean isTransient () {
+ return Modifier.isTransient(field.getModifiers());
+ }
+
+ /** Return true if the field includes the {@code volatile} modifier. */
+ public boolean isVolatile () {
+ return Modifier.isVolatile(field.getModifiers());
+ }
+
+ /** Return true if the field is a synthetic field. */
+ public boolean isSynthetic () {
+ return field.isSynthetic();
+ }
+
+ /** If the type of the field is parameterized, returns the Class object representing the parameter type at the specified index,
+ * null otherwise. */
+ public Class getElementType (int index) {
+ Type genericType = field.getGenericType();
+ if (genericType instanceof ParameterizedType) {
+ Type[] actualTypes = ((ParameterizedType)genericType).getActualTypeArguments();
+ if (actualTypes.length - 1 >= index) {
+ Type actualType = actualTypes[index];
+ if (actualType instanceof Class)
+ return (Class)actualType;
+ else if (actualType instanceof ParameterizedType)
+ return (Class)((ParameterizedType)actualType).getRawType();
+ else if (actualType instanceof GenericArrayType) {
+ Type componentType = ((GenericArrayType)actualType).getGenericComponentType();
+ if (componentType instanceof Class) return ArrayReflection.newInstance((Class)componentType, 0).getClass();
+ }
+ }
+ }
+ return null;
+ }
+
+ /** Returns the value of the field on the supplied object. */
+ public Object get (Object obj) throws ReflectionException {
+ try {
+ return field.get(obj);
+ } catch (IllegalArgumentException e) {
+ throw new ReflectionException("Object is not an instance of " + getDeclaringClass(), e);
+ } catch (IllegalAccessException e) {
+ throw new ReflectionException("Illegal access to field: " + getName(), e);
+ }
+ }
+
+ /** Sets the value of the field on the supplied object. */
+ public void set (Object obj, Object value) throws ReflectionException {
+ try {
+ field.set(obj, value);
+ } catch (IllegalArgumentException e) {
+ throw new ReflectionException("Argument not valid for field: " + getName(), e);
+ } catch (IllegalAccessException e) {
+ throw new ReflectionException("Illegal access to field: " + getName(), e);
+ }
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public boolean hasAnnotation(Class annotationClass) {
+ return field.getAnnotation(annotationClass) != null ? true: false;
+ }
+
+
+}
\ No newline at end of file
diff --git a/artemis/src/main/java/com/artemis/utils/reflect/Method.java b/artemis/src/main/java/com/artemis/utils/reflect/Method.java
new file mode 100644
index 000000000..080ae2751
--- /dev/null
+++ b/artemis/src/main/java/com/artemis/utils/reflect/Method.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright 2011 See AUTHORS file.
+ *
+ * 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 com.artemis.utils.reflect;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
+
+/** Provides information about, and access to, a single method on a class or interface.
+ * @author nexsoftware */
+public final class Method {
+
+ private final java.lang.reflect.Method method;
+
+ Method (java.lang.reflect.Method method) {
+ this.method = method;
+ }
+
+ /** Returns the name of the method. */
+ public String getName () {
+ return method.getName();
+ }
+
+ /** Returns a Class object that represents the formal return type of the method. */
+ public Class getReturnType () {
+ return method.getReturnType();
+ }
+
+ /** Returns an array of Class objects that represent the formal parameter types, in declaration order, of the method. */
+ public Class[] getParameterTypes () {
+ return method.getParameterTypes();
+ }
+
+ /** Returns the Class object representing the class or interface that declares the method. */
+ public Class getDeclaringClass () {
+ return method.getDeclaringClass();
+ }
+
+ public boolean isAccessible () {
+ return method.isAccessible();
+ }
+
+ public void setAccessible (boolean accessible) {
+ method.setAccessible(accessible);
+ }
+
+ /** Return true if the method includes the {@code abstract} modifier. */
+ public boolean isAbstract () {
+ return Modifier.isAbstract(method.getModifiers());
+ }
+
+ /** Return true if the method does not include any of the {@code private}, {@code protected}, or {@code public} modifiers. */
+ public boolean isDefaultAccess () {
+ return !isPrivate() && !isProtected() && !isPublic();
+ }
+
+ /** Return true if the method includes the {@code final} modifier. */
+ public boolean isFinal () {
+ return Modifier.isFinal(method.getModifiers());
+ }
+
+ /** Return true if the method includes the {@code private} modifier. */
+ public boolean isPrivate () {
+ return Modifier.isPrivate(method.getModifiers());
+ }
+
+ /** Return true if the method includes the {@code protected} modifier. */
+ public boolean isProtected () {
+ return Modifier.isProtected(method.getModifiers());
+ }
+
+ /** Return true if the method includes the {@code public} modifier. */
+ public boolean isPublic () {
+ return Modifier.isPublic(method.getModifiers());
+ }
+
+ /** Return true if the method includes the {@code native} modifier. */
+ public boolean isNative () {
+ return Modifier.isNative(method.getModifiers());
+ }
+
+ /** Return true if the method includes the {@code static} modifier. */
+ public boolean isStatic () {
+ return Modifier.isStatic(method.getModifiers());
+ }
+
+ /** Return true if the method takes a variable number of arguments. */
+ public boolean isVarArgs () {
+ return method.isVarArgs();
+ }
+
+ /** Invokes the underlying method on the supplied object with the supplied parameters. */
+ public Object invoke (Object obj, Object... args) throws ReflectionException {
+ try {
+ return method.invoke(obj, args);
+ } catch (IllegalArgumentException e) {
+ throw new ReflectionException("Illegal argument(s) supplied to method: " + getName(), e);
+ } catch (IllegalAccessException e) {
+ throw new ReflectionException("Illegal access to method: " + getName(), e);
+ } catch (InvocationTargetException e) {
+ throw new ReflectionException("Exception occurred in method: " + getName(), e);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/artemis/src/main/java/com/artemis/utils/reflect/ReflectionException.java b/artemis/src/main/java/com/artemis/utils/reflect/ReflectionException.java
new file mode 100644
index 000000000..a92502e6f
--- /dev/null
+++ b/artemis/src/main/java/com/artemis/utils/reflect/ReflectionException.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright 2011 See AUTHORS file.
+ *
+ * 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 com.artemis.utils.reflect;
+
+/** Thrown when an exception occurs during reflection.
+ * @author nexsoftware
+ */
+public class ReflectionException extends Exception {
+
+ private static final long serialVersionUID = -7146287043138864498L;
+
+ public ReflectionException () {
+ super();
+ }
+
+ public ReflectionException (String message) {
+ super(message);
+ }
+
+ public ReflectionException (Throwable cause) {
+ super(cause);
+ }
+
+ public ReflectionException (String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
\ No newline at end of file
diff --git a/artemis/src/test/java/com/artemis/ComponentPoolTest.java b/artemis/src/test/java/com/artemis/ComponentPoolTest.java
index ae81f3793..e8f31df09 100644
--- a/artemis/src/test/java/com/artemis/ComponentPoolTest.java
+++ b/artemis/src/test/java/com/artemis/ComponentPoolTest.java
@@ -19,7 +19,7 @@ public void reuse_pooled_components() throws Exception
assertTrue(c1 == c1b);
}
- static final class SimplePooled extends PooledComponent {
+ public static final class SimplePooled extends PooledComponent {
@Override
public void reset() {}
diff --git a/pom.xml b/pom.xml
index 39366b109..3bb5df689 100644
--- a/pom.xml
+++ b/pom.xml
@@ -75,6 +75,7 @@
artemis-weaverartemis-mavenartemis-test
+ artemis-gwt