Skip to content

Commit

Permalink
Implremented generics for reverse, javaToJS methods
Browse files Browse the repository at this point in the history
  • Loading branch information
LatvianModder committed May 22, 2024
1 parent 7be7ed3 commit 8c7aee1
Show file tree
Hide file tree
Showing 16 changed files with 110 additions and 141 deletions.
71 changes: 60 additions & 11 deletions src/main/java/dev/latvian/mods/rhino/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
import dev.latvian.mods.rhino.ast.ScriptNode;
import dev.latvian.mods.rhino.classfile.ClassFileWriter.ClassFileFormatException;
import dev.latvian.mods.rhino.regexp.RegExp;
import dev.latvian.mods.rhino.type.TypeUtils;
import dev.latvian.mods.rhino.util.ArrayValueProvider;
import dev.latvian.mods.rhino.util.ClassVisibilityContext;
import dev.latvian.mods.rhino.util.CustomJavaToJsWrapper;
import dev.latvian.mods.rhino.util.JavaSetWrapper;
import dev.latvian.mods.rhino.util.TypeUtils;
import dev.latvian.mods.rhino.util.wrap.TypeWrapperFactory;
import org.jetbrains.annotations.Nullable;

Expand Down Expand Up @@ -1134,21 +1134,62 @@ public Scriptable wrapJavaClass(Scriptable scope, Class<?> javaClass) {
*/
public Scriptable wrapAsJavaObject(Scriptable scope, Object javaObject, Class<?> staticType, Type genericType) {
if (javaObject instanceof CustomJavaToJsWrapper w) {
return w.convertJavaToJs(this, scope, staticType);
return w.convertJavaToJs(this, scope, staticType, genericType);
}

CustomJavaToJsWrapper w = factory.wrapCustomJavaToJs(javaObject);
if (javaObject instanceof Map map) {
Class<?> kType = null;
Type kGenericType = null;
Class<?> vType = null;
Type vGenericType = null;

if (w != null) {
return w.convertJavaToJs(this, scope, staticType);
}
if (staticType != null && genericType instanceof ParameterizedType pt) {
var types = pt.getActualTypeArguments();
var kRaw = types.length == 2 ? TypeUtils.getRawType(types[0]) : Object.class;
var vRaw = types.length == 2 ? TypeUtils.getRawType(types[1]) : Object.class;

if (javaObject instanceof Map map) {
return new NativeJavaMap(this, scope, map, map);
if (kRaw != null && kRaw != Object.class) {
kType = kRaw;
kGenericType = types[0];
}

if (vRaw != null && vRaw != Object.class) {
vType = vRaw;
vGenericType = types[1];
}
}

return new NativeJavaMap(this, scope, map, map, kType, kGenericType, vType, vGenericType);
} else if (javaObject instanceof List list) {
return new NativeJavaList(this, scope, list, list);
Class<?> lType = null;
Type lGenericType = null;

if (staticType != null && genericType instanceof ParameterizedType pt) {
var types = pt.getActualTypeArguments();
var raw = types.length == 1 ? TypeUtils.getRawType(types[0]) : Object.class;

if (raw != null && raw != Object.class) {
lType = raw;
lGenericType = pt.getActualTypeArguments()[0];
}
}

return new NativeJavaList(this, scope, list, list, lType, lGenericType);
} else if (javaObject instanceof Set<?> set) {
return new NativeJavaList(this, scope, set, new JavaSetWrapper<>(set));
Class<?> lType = null;
Type lGenericType = null;

if (staticType != null && genericType instanceof ParameterizedType pt) {
var types = pt.getActualTypeArguments();
var raw = types.length == 1 ? TypeUtils.getRawType(types[0]) : Object.class;

if (raw != null && raw != Object.class) {
lType = raw;
lGenericType = pt.getActualTypeArguments()[0];
}
}

return new NativeJavaList(this, scope, set, new JavaSetWrapper<>(set), lType, lGenericType);
}

// TODO: Wrap Gson
Expand Down Expand Up @@ -1356,12 +1397,16 @@ public Object createInterfaceAdapter(Class<?> type, Type genericType, Scriptable
}

public Object javaToJS(Object value, Scriptable scope) {
return javaToJS(value, scope, null, null);
}

public Object javaToJS(Object value, Scriptable scope, @Nullable Class<?> target, @Nullable Type genericTarget) {
if (value instanceof String || value instanceof Number || value instanceof Boolean || value instanceof Scriptable) {
return value;
} else if (value instanceof Character) {
return String.valueOf(((Character) value).charValue());
} else {
return wrap(scope, value, null, null);
return wrap(scope, value, target, genericTarget);
}
}

Expand Down Expand Up @@ -1497,6 +1542,10 @@ protected Object internalJsToJava(Object from, Class<?> target, Type genericTarg

Object unwrappedValue = Wrapper.unwrapped(from);

if (unwrappedValue instanceof TypeWrapperFactory<?> f) {
return f.wrap(this, unwrappedValue, target, genericTarget);
}

TypeWrapperFactory<?> typeWrapper = typeWrappers == null ? null : typeWrappers.getWrapperFactory(unwrappedValue, target, genericTarget);

if (typeWrapper != null) {
Expand Down
52 changes: 1 addition & 51 deletions src/main/java/dev/latvian/mods/rhino/ContextFactory.java
Original file line number Diff line number Diff line change
@@ -1,28 +1,14 @@
package dev.latvian.mods.rhino;

import dev.latvian.mods.rhino.util.CustomJavaToJsWrapper;
import dev.latvian.mods.rhino.util.CustomJavaToJsWrapperProvider;
import dev.latvian.mods.rhino.util.CustomJavaToJsWrapperProviderHolder;
import dev.latvian.mods.rhino.util.wrap.TypeWrappers;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

public class ContextFactory {
private final ThreadLocal<Context> currentContext;
private TypeWrappers typeWrappers;
private final List<CustomJavaToJsWrapperProviderHolder<?>> customScriptableWrappers;
private final Map<Class<?>, CustomJavaToJsWrapperProvider> customScriptableWrapperCache;
private final TypeWrappers typeWrappers;

public ContextFactory() {
this.currentContext = ThreadLocal.withInitial(this::createContext);
this.typeWrappers = new TypeWrappers();
this.customScriptableWrappers = new ArrayList<>();
this.customScriptableWrapperCache = new HashMap<>();
}

protected Context createContext() {
Expand All @@ -43,40 +29,4 @@ public Context enter() {
public synchronized TypeWrappers getTypeWrappers() {
return typeWrappers;
}

@Nullable
@SuppressWarnings("unchecked")
public synchronized CustomJavaToJsWrapper wrapCustomJavaToJs(Object javaObject) {
if (customScriptableWrappers.isEmpty()) {
return null;
}

var provider = customScriptableWrapperCache.get(javaObject.getClass());

if (provider == null) {
for (CustomJavaToJsWrapperProviderHolder wrapper : customScriptableWrappers) {
provider = wrapper.create(javaObject);

if (provider != null) {
break;
}
}

if (provider == null) {
provider = CustomJavaToJsWrapperProvider.NONE;
}

customScriptableWrapperCache.put(javaObject.getClass(), provider);
}

return provider.create(javaObject);
}

public <T> void addCustomJavaToJsWrapper(Predicate<T> predicate, CustomJavaToJsWrapperProvider<T> provider) {
customScriptableWrappers.add(new CustomJavaToJsWrapperProviderHolder<>(predicate, provider));
}

public <T> void addCustomJavaToJsWrapper(Class<T> type, CustomJavaToJsWrapperProvider<T> provider) {
addCustomJavaToJsWrapper(new CustomJavaToJsWrapperProviderHolder.PredicateFromClass<>(type), provider);
}
}
22 changes: 8 additions & 14 deletions src/main/java/dev/latvian/mods/rhino/NativeJavaList.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
package dev.latvian.mods.rhino;

import dev.latvian.mods.rhino.util.Deletable;
import dev.latvian.mods.rhino.util.ValueUnwrapper;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.Type;
Expand All @@ -23,18 +22,12 @@ public class NativeJavaList extends NativeJavaObject {
public final List list;
public final Class<?> listType;
public final Type listGenericType;
private final ValueUnwrapper valueUnwrapper;

public NativeJavaList(Context cx, Scriptable scope, Object jo, List list, @Nullable Class<?> listType, Type listGenericType, ValueUnwrapper valueUnwrapper) {
public NativeJavaList(Context cx, Scriptable scope, Object jo, List list, @Nullable Class<?> listType, @Nullable Type listGenericType) {
super(scope, jo, jo.getClass(), cx);
this.list = list;
this.listType = listType;
this.listGenericType = listGenericType;
this.valueUnwrapper = valueUnwrapper;
}

public NativeJavaList(Context cx, Scriptable scope, Object jo, List list) {
this(cx, scope, jo, list, null, null, ValueUnwrapper.DEFAULT);
}

@Override
Expand All @@ -61,8 +54,9 @@ public boolean has(Context cx, Symbol key, Scriptable start) {
@Override
public Object get(Context cx, int index, Scriptable start) {
if (isWithValidIndex(index)) {
return valueUnwrapper.unwrap(cx, this, list.get(index));
return cx.javaToJS(list.get(index), start, listType, listGenericType);
}

return Undefined.INSTANCE;
}

Expand Down Expand Up @@ -286,10 +280,10 @@ private Object reduce(Context cx, Object[] args) {
}

BinaryOperator operator = (BinaryOperator) args[0];
Object o = valueUnwrapper.unwrap(cx, this, list.get(0));
Object o = get(cx, 0, this);

for (int i = 1; i < list.size(); i++) {
o = valueUnwrapper.unwrap(cx, this, operator.apply(o, valueUnwrapper.unwrap(cx, this, list.get(i))));
o = operator.apply(o, get(cx, i, this));
}

return o;
Expand All @@ -299,14 +293,14 @@ private Object reduceRight(Context cx, Object[] args) {
if (list.isEmpty()) {
return Undefined.INSTANCE;
} else if (list.size() == 1) {
return list.get(0);
return list.get(0); // might not be correct start index
}

BinaryOperator operator = (BinaryOperator) args[0];
Object o = valueUnwrapper.unwrap(cx, this, list.get(0));
Object o = get(cx, 0, this);

for (int i = list.size() - 1; i >= 1; i--) {
o = valueUnwrapper.unwrap(cx, this, operator.apply(o, valueUnwrapper.unwrap(cx, this, list.get(i))));
o = operator.apply(o, get(cx, i, this));
}

return o;
Expand Down
13 changes: 3 additions & 10 deletions src/main/java/dev/latvian/mods/rhino/NativeJavaMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
package dev.latvian.mods.rhino;

import dev.latvian.mods.rhino.util.Deletable;
import dev.latvian.mods.rhino.util.ValueUnwrapper;

import java.lang.reflect.Type;
import java.util.ArrayList;
Expand All @@ -20,20 +19,14 @@ public class NativeJavaMap extends NativeJavaObject {
public final Type mapKeyGenericType;
public final Class<?> mapValueType;
public final Type mapValueGenericType;
private final ValueUnwrapper valueUnwrapper;

public NativeJavaMap(Context cx, Scriptable scope, Object jo, Map map, Class<?> mapKeyType, Type mapKeyGenericType, Class<?> mapValueType, Type mapValueGenericType, ValueUnwrapper valueUnwrapper) {
public NativeJavaMap(Context cx, Scriptable scope, Object jo, Map map, Class<?> mapKeyType, Type mapKeyGenericType, Class<?> mapValueType, Type mapValueGenericType) {
super(scope, jo, jo.getClass(), cx);
this.map = map;
this.mapKeyType = mapKeyType;
this.mapKeyGenericType = mapKeyGenericType;
this.mapValueType = mapValueType;
this.mapValueGenericType = mapValueGenericType;
this.valueUnwrapper = valueUnwrapper;
}

public NativeJavaMap(Context cx, Scriptable scope, Object jo, Map map) {
this(cx, scope, jo, map, null, null, null, null, ValueUnwrapper.DEFAULT);
}

@Override
Expand All @@ -60,15 +53,15 @@ public boolean has(Context cx, int index, Scriptable start) {
@Override
public Object get(Context cx, String name, Scriptable start) {
if (map.containsKey(name)) {
return valueUnwrapper.unwrap(cx, this, map.get(name));
return cx.javaToJS(map.get(cx.jsToJava(name, mapKeyType, mapKeyGenericType)), start, mapValueType, mapValueGenericType);
}
return super.get(cx, name, start);
}

@Override
public Object get(Context cx, int index, Scriptable start) {
if (map.containsKey(index)) {
return valueUnwrapper.unwrap(cx, this, map.get(index));
return cx.javaToJS(map.get(cx.jsToJava(index, mapKeyType, mapKeyGenericType)), start, mapValueType, mapValueGenericType);
}
return super.get(cx, index, start);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package dev.latvian.mods.rhino.util;
package dev.latvian.mods.rhino.type;

import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
Expand All @@ -8,8 +8,6 @@
import java.lang.reflect.WildcardType;

public class TypeUtils {
public static final Type[] NO_TYPES = new Type[0];

public static Class<?> getRawType(Type type) {
if (type instanceof Class<?> clz) {
return clz;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import dev.latvian.mods.rhino.Context;
import dev.latvian.mods.rhino.Scriptable;

import java.lang.reflect.Type;

@FunctionalInterface
public interface CustomJavaToJsWrapper {
Scriptable convertJavaToJs(Context cx, Scriptable scope, Class<?> staticType);
Scriptable convertJavaToJs(Context cx, Scriptable scope, Class<?> staticType, Type genericType);
}

This file was deleted.

This file was deleted.

11 changes: 0 additions & 11 deletions src/main/java/dev/latvian/mods/rhino/util/ValueUnwrapper.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.Type;
import java.util.LinkedHashMap;
import java.util.IdentityHashMap;
import java.util.Map;

/**
* @author LatvianModder
*/
public class TypeWrappers {
public final Map<Class<?>, TypeWrapper<?>> wrappers = new LinkedHashMap<>();
public final Map<Class<?>, TypeWrapper<?>> wrappers = new IdentityHashMap<>();

public <T> void register(Class<T> target, TypeWrapperValidator validator, TypeWrapperFactory<T> factory) {
if (target == null || target == Object.class) {
Expand Down
Loading

0 comments on commit 8c7aee1

Please sign in to comment.