Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Artemis-odb Support, working on Linux and HyperLap2D Test #43

Merged
merged 2 commits into from
Jan 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.artemis.utils.reflect;

/** Provides information about, and access to, an annotation of a field, class or interface.
* @author dludwig */
public final class Annotation {

private java.lang.annotation.Annotation annotation;

Annotation (java.lang.annotation.Annotation annotation) {
this.annotation = annotation;
}

@SuppressWarnings("unchecked")
public <T extends java.lang.annotation.Annotation> T getAnnotation (Class<T> annotationType) {
if (annotation.annotationType().equals(annotationType)) {
return (T) annotation;
}
return null;
}

public Class<? extends java.lang.annotation.Annotation> getAnnotationType () {
return annotation.annotationType();
}
}
230 changes: 230 additions & 0 deletions backends/backend-teavm/emu/com/artemis/utils/reflect/Field.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
package com.artemis.utils.reflect;

import com.badlogic.gdx.utils.reflect.ArrayReflection;
import com.badlogic.gdx.utils.reflect.ReflectionException;
import com.github.xpenatan.gdx.backends.teavm.plugins.TeaReflectionSupplier;
import com.github.xpenatan.gdx.backends.teavm.util.GenericTypeProvider;
import org.teavm.metaprogramming.*;
import org.teavm.metaprogramming.reflect.ReflectField;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

@CompileTime
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 true;
}

public void setAccessible (boolean 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 () {
// TODO
// return Modifier.isFinal(field.getModifiers());
return false;
}

/** Return true if the field includes the {@code private} modifier. */
public boolean isPrivate () {
// TODO
// return Modifier.isPrivate(field.getModifiers());
return false;
}

/** Return true if the field includes the {@code protected} modifier. */
public boolean isProtected () {
// TODO
// return Modifier.isProtected(field.getModifiers());
return false;
}

/** Return true if the field includes the {@code public} modifier. */
public boolean isPublic () {
// TODO
// return Modifier.isPublic(field.getModifiers());
return false;
}

/** Return true if the field includes the {@code static} modifier. */
public boolean isStatic () {
// TODO
// return Modifier.isStatic(field.getModifiers());
return false;
}

/** Return true if the field includes the {@code transient} modifier. */
public boolean isTransient () {
// TODO
// return Modifier.isTransient(field.getModifiers());
return false;
}

/** Return true if the field includes the {@code volatile} modifier. */
public boolean isVolatile () {
// TODO
// return Modifier.isVolatile(field.getModifiers());
return false;
}

/** Return true if the field is a synthetic field. */
public boolean isSynthetic () {
return field.isSynthetic();
}

private static Class<?> getActualType(Type actualType) {
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;
}

@Meta
public static native Class getElementType(Class<?> type, String fieldName, int index);
private static void getElementType(ReflectClass<?> cls, Value<String> fieldNameValue, Value<Integer> indexValue) {
String name = cls.getName();
if(!TeaReflectionSupplier.containsReflection(name)) {
Metaprogramming.unsupportedCase();
return;
}
ClassLoader classLoader = Metaprogramming.getClassLoader();
GenericTypeProvider genericTypeProvider = new GenericTypeProvider(classLoader);

boolean found = false;
Value<Class> result = Metaprogramming.lazy(() -> null);
for (ReflectField field : cls.getDeclaredFields()) {
java.lang.reflect.Field javaField = genericTypeProvider.findField(field);
Type genericType = javaField.getGenericType();
if (genericType instanceof ParameterizedType) {
Type[] actualTypes = ((ParameterizedType) genericType).getActualTypeArguments();

if(actualTypes!= null) {
for(int i = 0; i < actualTypes.length; i++) {
Class actualType = getActualType(actualTypes[i]);
if(actualType == null)
continue;
found = true;
final int index = i;

String fieldName = field.getName();
Value<Class> existing = result;
result = Metaprogramming.lazy(() -> {
if(index == indexValue.get()) {
if(fieldName.equals(fieldNameValue.get())) {
return actualType;
}
}
return existing.get();
});
}
}
}
}
if(!found) {
Metaprogramming.unsupportedCase();
return;
}
Value<Class> type = result;
Metaprogramming.exit(() -> type.get());
}


/** 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) {
Class<?> declaringClass = field.getDeclaringClass();
return getElementType(declaringClass, field.getName(), index);
}

public <T extends java.lang.annotation.Annotation> T getAnnotation(Class<T> annotationClass) {
final Annotation declaredAnnotation = getDeclaredAnnotation(annotationClass);
return declaredAnnotation != null ? declaredAnnotation.getAnnotation(annotationClass) : null;
}

/** Returns true if the field includes an annotation of the provided class type. */
public boolean isAnnotationPresent (Class<? extends java.lang.annotation.Annotation> annotationType) {
return field.isAnnotationPresent(annotationType);
}

/** Returns an array of {@link Annotation} objects reflecting all annotations declared by this field,
* or an empty array if there are none. Does not include inherited annotations. */
public Annotation[] getDeclaredAnnotations () {
java.lang.annotation.Annotation[] annotations = field.getDeclaredAnnotations();
Annotation[] result = new Annotation[annotations.length];
for (int i = 0; i < annotations.length; i++) {
result[i] = new Annotation(annotations[i]);
}
return result;
}

/** Returns an {@link Annotation} object reflecting the annotation provided, or null of this field doesn't
* have such an annotation. This is a convenience function if the caller knows already which annotation
* type he's looking for. */
public Annotation getDeclaredAnnotation (Class<? extends java.lang.annotation.Annotation> annotationType) {
java.lang.annotation.Annotation[] annotations = field.getDeclaredAnnotations();
if (annotations == null) {
return null;
}
for (java.lang.annotation.Annotation annotation : annotations) {
if (annotation.annotationType().equals(annotationType)) {
return new Annotation(annotation);
}
}
return null;
}

/** Returns the value of the field on the supplied object.
* @throws IllegalAccessException
* @throws IllegalArgumentException */
public Object get (Object obj) throws IllegalArgumentException, IllegalAccessException {
return field.get(obj);
}

/** Sets the value of the field on the supplied object.
* @throws ReflectionException */
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);
}
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,15 @@ public Object get (Object obj) throws IllegalArgumentException, IllegalAccessExc
}

/** Sets the value of the field on the supplied object.
* @throws IllegalAccessException
* @throws IllegalArgumentException */
public void set (Object obj, Object value) throws IllegalArgumentException, IllegalAccessException{
field.set(obj, value);
* @throws ReflectionException */
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);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public class TeaBuildConfiguration extends WebBuildConfiguration {
public String mainApplicationClass;
public String webappPath;
public final Array<URL> additionalClasspath = new Array<>();
public final Array<String> reflectionInclude = new Array<>();
public final Array<String> reflectionExclude = new Array<>();

@Override
public String getMainClass() {
Expand Down Expand Up @@ -49,6 +51,16 @@ public boolean minifying() {
return obfuscate;
}

@Override
public Array<String> getReflectionInclude() {
return reflectionInclude;
}

@Override
public Array<String> getReflectionExclude() {
return reflectionExclude;
}

@Override
public void assetsClasspath(Array<String> classPaths) {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@
import org.teavm.vm.*;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;


/**
Expand All @@ -32,6 +35,33 @@ public static void build(WebBuildConfiguration configuration) {

public static void build(WebBuildConfiguration configuration, TeaProgressListener progressListener) {
addDefaultReflectionClasses();
for (URL classPath : configuration.getAdditionalClasspath()) {
try {
ZipInputStream zip = new ZipInputStream(classPath.openStream());
WebBuildConfiguration.logHeader("Automatic Reflection Include");
for (ZipEntry entry = zip.getNextEntry(); entry != null; entry = zip.getNextEntry()) {
if (!entry.isDirectory() && entry.getName().endsWith(".class")) {
// This ZipEntry represents a class. Now, what class does it represent?
String className = entry.getName().replace('/', '.'); // including ".class"
String name = className.substring(0, className.length() - ".class".length());
boolean add = false;
for (String toInclude : configuration.getReflectionInclude()) {
if (name.startsWith(toInclude)) add = true;
}
for (String toExclude : configuration.getReflectionExclude()) {
if (name.startsWith(toExclude)) add = false;
}

if (add) {
WebBuildConfiguration.log("Include class: " + name);
TeaReflectionSupplier.addReflectionClass(name);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}

URL[] urLs = ((URLClassLoader) (Thread.currentThread().getContextClassLoader())).getURLs();

Expand Down Expand Up @@ -90,13 +120,14 @@ public static void build(WebBuildConfiguration configuration, TeaProgressListene

System.out.println("targetDirectory: " + webappDirectory);

File setTargetDirectory = new File(webappDirectory + "\\" + webappName + "\\" + "teavm");
File setTargetDirectory = new File(webappDirectory + File.separator + webappName + File.separator + "teavm");
String setTargetFileName = "app.js";
boolean setMinifying = configuration.minifying();
String mainClass = configuration.getMainClass();
TeaClassTransformer.applicationListener = configuration.getApplicationListenerClass();

File setCacheDirectory = new File("C:\\TeaVMCache");
String tmpdir = System.getProperty("java.io.tmpdir");
File setCacheDirectory = new File(tmpdir + File.separator + "TeaVMCache");
boolean setIncremental = false;

tool.setClassLoader(classLoader);
Expand All @@ -116,16 +147,16 @@ public static void build(WebBuildConfiguration configuration, TeaProgressListene
tool.setTargetType(TeaVMTargetType.JAVASCRIPT);
Properties properties = tool.getProperties();

properties.put("teavm.libgdx.fsJsonPath", webappDirectory + "\\" + webappName + "\\" + "filesystem.json");
properties.put("teavm.libgdx.warAssetsDirectory", webappDirectory + "\\" + webappName + "\\" + "assets");
properties.put("teavm.libgdx.fsJsonPath", webappDirectory + File.separator + webappName + File.separator + "filesystem.json");
properties.put("teavm.libgdx.warAssetsDirectory", webappDirectory + File.separator + webappName + File.separator + "assets");

Array<String> webappAssetsFiles = new Array<>();
webappAssetsFiles.add(webappName);
AssetsCopy.copy(classLoader, webappAssetsFiles, new Array<>(), webappDirectory, false);

WebBuildConfiguration.logHeader("Copying Assets");

String assetsOutputPath = webappDirectory + "\\" + webappName + "\\assets";
String assetsOutputPath = webappDirectory + File.separator + webappName + File.separator + "assets";
Array<File> assetsPaths = new Array<>();
Array<String> classPathAssetsFiles = new Array<>();
assetsDefaultClasspath(classPathAssetsFiles);
Expand Down Expand Up @@ -370,7 +401,7 @@ enum ACCEPT_STATE {
}

public interface TeaProgressListener {
public void onSuccess(boolean success);
public void onProgress(float progress);
void onSuccess(boolean success);
void onProgress(float progress);
}
}
Loading