mirror of
https://github.com/konsoletyper/teavm.git
synced 2024-11-27 01:30:35 +08:00
JS: add reflection support for constructors
This commit is contained in:
parent
c4c5635f88
commit
4171d468d4
@ -161,9 +161,9 @@ public class ReflectionDependencyListener extends AbstractDependencyListener {
|
||||
ClassReader cls = agent.getClassSource().get(reflectedType.getName());
|
||||
for (MethodDescriptor methodDescriptor : accessibleMethods) {
|
||||
MethodReader calledMethod = cls.getMethod(methodDescriptor);
|
||||
MethodDependency calledMethodDep = agent.linkMethod(method.getReference(), location);
|
||||
MethodDependency calledMethodDep = agent.linkMethod(calledMethod.getReference(), location);
|
||||
calledMethodDep.use();
|
||||
for (int i = 0; i < methodDescriptor.parameterCount(); ++i) {
|
||||
for (int i = 0; i < calledMethod.parameterCount(); ++i) {
|
||||
propagateSet(agent, methodDescriptor.parameterType(i), method.getVariable(1).getArrayItem(),
|
||||
calledMethodDep.getVariable(i + 1), location);
|
||||
}
|
||||
|
@ -23,6 +23,15 @@ import org.teavm.model.MethodReference;
|
||||
public class ConverterInjector implements Injector {
|
||||
@Override
|
||||
public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
|
||||
context.writeExpr(context.getArgument(0));
|
||||
switch (methodRef.getName()) {
|
||||
case "toJava":
|
||||
case "fromJava":
|
||||
context.writeExpr(context.getArgument(0));
|
||||
break;
|
||||
case "arrayFromJava":
|
||||
context.writeExpr(context.getArgument(0));
|
||||
context.getWriter().append(".data");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,4 +25,10 @@ public interface JSClass extends PlatformClassMetadata {
|
||||
|
||||
@JSProperty
|
||||
void setFields(JSArray<JSField> fields);
|
||||
|
||||
@JSProperty
|
||||
JSArray<JSMethodMember> getMethods();
|
||||
|
||||
@JSProperty
|
||||
void setMethods(JSArray<JSMethodMember> methods);
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ import org.teavm.jso.JSProperty;
|
||||
import org.teavm.platform.PlatformClass;
|
||||
import org.teavm.platform.PlatformSequence;
|
||||
|
||||
public interface JSConstructor extends JSMember {
|
||||
public interface JSMethodMember extends JSMember {
|
||||
@JSProperty
|
||||
PlatformSequence<PlatformClass> getParameterTypes();
|
||||
|
@ -18,18 +18,31 @@ package org.teavm.classlib.java.lang;
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import org.teavm.backend.javascript.codegen.SourceWriter;
|
||||
import org.teavm.backend.javascript.rendering.Precedence;
|
||||
import org.teavm.backend.javascript.rendering.RenderingUtil;
|
||||
import org.teavm.backend.javascript.spi.Generator;
|
||||
import org.teavm.backend.javascript.spi.GeneratorContext;
|
||||
import org.teavm.backend.javascript.spi.Injector;
|
||||
import org.teavm.backend.javascript.spi.InjectorContext;
|
||||
import org.teavm.classlib.impl.ReflectionDependencyListener;
|
||||
import org.teavm.dependency.DependencyAgent;
|
||||
import org.teavm.dependency.DependencyPlugin;
|
||||
import org.teavm.dependency.MethodDependency;
|
||||
import org.teavm.model.CallLocation;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.FieldReader;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.MemberReader;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
public class ClassGenerator implements Generator {
|
||||
public class ClassGenerator implements Generator, Injector, DependencyPlugin {
|
||||
private static final FieldReference platformClassField =
|
||||
new FieldReference(Class.class.getName(), "platformClass");
|
||||
|
||||
@Override
|
||||
public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException {
|
||||
switch (methodRef.getName()) {
|
||||
@ -39,6 +52,27 @@ public class ClassGenerator implements Generator {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(InjectorContext context, MethodReference methodRef) throws IOException {
|
||||
switch (methodRef.getName()) {
|
||||
case "newEmptyInstance":
|
||||
context.getWriter().append("new ");
|
||||
context.writeExpr(context.getArgument(0), Precedence.MEMBER_ACCESS);
|
||||
context.getWriter().append('.').appendField(platformClassField);
|
||||
context.getWriter().append("()");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void methodReached(DependencyAgent agent, MethodDependency method, CallLocation location) {
|
||||
switch (method.getReference().getName()) {
|
||||
case "newEmptyInstance":
|
||||
method.getVariable(0).getClassValueNode().connect(method.getResult());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void generateCreateMetadata(GeneratorContext context, SourceWriter writer) throws IOException {
|
||||
ReflectionDependencyListener reflection = context.getService(ReflectionDependencyListener.class);
|
||||
for (String className : reflection.getClassesWithReflectableFields()) {
|
||||
@ -83,10 +117,32 @@ public class ClassGenerator implements Generator {
|
||||
private void generateCreateMethodsForClass(GeneratorContext context, SourceWriter writer, String className)
|
||||
throws IOException {
|
||||
ReflectionDependencyListener reflection = context.getService(ReflectionDependencyListener.class);
|
||||
Set<MethodDescriptor> accessibleMethods = reflection.getAccessibleMethods(className);
|
||||
|
||||
ClassReader cls = context.getClassSource().get(className);
|
||||
writer.appendClass(className).append(".$meta.methods").ws().append('=').ws().append('[').indent();
|
||||
|
||||
generateCreateMembers(writer, cls.getMethods(), method -> {
|
||||
appendProperty(writer, "parameterTypes", false, () -> {
|
||||
writer.append('[');
|
||||
for (int i = 0; i < method.parameterCount(); ++i) {
|
||||
if (i > 0) {
|
||||
writer.append(',').ws();
|
||||
}
|
||||
writer.append(context.typeToClassString(method.parameterType(i)));
|
||||
}
|
||||
writer.append(']');
|
||||
});
|
||||
|
||||
appendProperty(writer, "callable", false, () -> {
|
||||
if (accessibleMethods != null && accessibleMethods.contains(method.getDescriptor())) {
|
||||
renderCallable(writer, method);
|
||||
} else {
|
||||
writer.append("null");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
writer.outdent().append("];").softNewLine();
|
||||
}
|
||||
|
||||
@ -109,8 +165,6 @@ public class ClassGenerator implements Generator {
|
||||
renderer.render(member);
|
||||
writer.outdent().softNewLine().append("}");
|
||||
}
|
||||
|
||||
writer.outdent().append("];").softNewLine();
|
||||
}
|
||||
|
||||
private void appendProperty(SourceWriter writer, String name, boolean first, Fragment value) throws IOException {
|
||||
@ -140,9 +194,39 @@ public class ClassGenerator implements Generator {
|
||||
writer.outdent().append("}");
|
||||
}
|
||||
|
||||
private void initClass(SourceWriter writer, FieldReader field) throws IOException {
|
||||
if (field.hasModifier(ElementModifier.STATIC)) {
|
||||
writer.appendClass(field.getOwnerName()).append("_$callClinit();").softNewLine();
|
||||
private void renderCallable(SourceWriter writer, MethodReader method) throws IOException {
|
||||
writer.append("function(obj,").ws().append("args)").ws().append("{").indent().softNewLine();
|
||||
|
||||
initClass(writer, method);
|
||||
|
||||
if (method.getResultType() != ValueType.VOID) {
|
||||
writer.append("return ");
|
||||
}
|
||||
if (method.hasModifier(ElementModifier.STATIC)) {
|
||||
writer.appendMethodBody(method.getReference());
|
||||
} else {
|
||||
writer.append("obj.").appendMethod(method.getDescriptor());
|
||||
}
|
||||
|
||||
writer.append('(');
|
||||
for (int i = 0; i < method.parameterCount(); ++i) {
|
||||
if (i > 0) {
|
||||
writer.append(',').ws();
|
||||
}
|
||||
int index = i;
|
||||
unboxIfNecessary(writer, method.parameterType(i), () -> writer.append("args[" + index + "]"));
|
||||
}
|
||||
writer.append(");").softNewLine();
|
||||
|
||||
if (method.getResultType() == ValueType.VOID) {
|
||||
writer.append("return null;").softNewLine();
|
||||
}
|
||||
writer.outdent().append("}");
|
||||
}
|
||||
|
||||
private void initClass(SourceWriter writer, MemberReader member) throws IOException {
|
||||
if (member.hasModifier(ElementModifier.STATIC)) {
|
||||
writer.appendClass(member.getOwnerName()).append("_$callClinit();").softNewLine();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,17 +25,21 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.teavm.backend.javascript.spi.GeneratedBy;
|
||||
import org.teavm.backend.javascript.spi.InjectedBy;
|
||||
import org.teavm.classlib.impl.DeclaringClassMetadataGenerator;
|
||||
import org.teavm.classlib.impl.reflection.Flags;
|
||||
import org.teavm.classlib.impl.reflection.JSClass;
|
||||
import org.teavm.classlib.impl.reflection.JSField;
|
||||
import org.teavm.classlib.impl.reflection.JSMethodMember;
|
||||
import org.teavm.classlib.java.lang.annotation.TAnnotation;
|
||||
import org.teavm.classlib.java.lang.reflect.TAnnotatedElement;
|
||||
import org.teavm.dependency.PluggableDependency;
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.DelegateTo;
|
||||
import org.teavm.classlib.java.lang.reflect.TConstructor;
|
||||
import org.teavm.classlib.java.lang.reflect.TField;
|
||||
import org.teavm.classlib.java.lang.reflect.TModifier;
|
||||
import org.teavm.dependency.PluggableDependency;
|
||||
import org.teavm.jso.core.JSArray;
|
||||
import org.teavm.platform.Platform;
|
||||
import org.teavm.platform.PlatformClass;
|
||||
@ -53,6 +57,7 @@ public class TClass<T> extends TObject implements TAnnotatedElement {
|
||||
private Map<TClass<?>, TAnnotation> annotationsByType;
|
||||
private TField[] declaredFields;
|
||||
private TField[] fields;
|
||||
private TConstructor<T>[] declaredConstructors;
|
||||
private static boolean reflectionInitialized;
|
||||
|
||||
private TClass(PlatformClass platformClass) {
|
||||
@ -235,6 +240,77 @@ public class TClass<T> extends TObject implements TAnnotatedElement {
|
||||
return null;
|
||||
}
|
||||
|
||||
@InjectedBy(ClassGenerator.class)
|
||||
@PluggableDependency(ClassGenerator.class)
|
||||
public native <T> T newEmptyInstance();
|
||||
|
||||
@SuppressWarnings({ "raw", "unchecked" })
|
||||
public TConstructor<?>[] getDeclaredConstructors() throws TSecurityException {
|
||||
if (declaredConstructors == null) {
|
||||
initReflection();
|
||||
JSClass jsClass = (JSClass) getPlatformClass().getMetadata();
|
||||
JSArray<JSMethodMember> jsMethods = jsClass.getMethods();
|
||||
declaredConstructors = new TConstructor[jsMethods.getLength()];
|
||||
int count = 0;
|
||||
for (int i = 0; i < jsMethods.getLength(); ++i) {
|
||||
JSMethodMember jsMethod = jsMethods.get(i);
|
||||
if (!jsMethod.getName().equals("<init>")) {
|
||||
continue;
|
||||
}
|
||||
PlatformSequence<PlatformClass> jsParameterTypes = jsMethod.getParameterTypes();
|
||||
TClass<?>[] parameterTypes = new TClass<?>[jsParameterTypes.getLength()];
|
||||
for (int j = 0; j < parameterTypes.length; ++j) {
|
||||
parameterTypes[j] = getClass(jsParameterTypes.get(j));
|
||||
}
|
||||
declaredConstructors[count++] = new TConstructor<T>(this, jsMethod.getName(), jsMethod.getModifiers(),
|
||||
jsMethod.getAccessLevel(), parameterTypes, jsMethod.getCallable());
|
||||
}
|
||||
declaredConstructors = Arrays.copyOf(declaredConstructors, count);
|
||||
}
|
||||
return declaredConstructors;
|
||||
}
|
||||
|
||||
public TConstructor<?>[] getConstructors() throws TSecurityException {
|
||||
TConstructor<?>[] declaredConstructors = getDeclaredConstructors();
|
||||
TConstructor<?>[] constructors = new TConstructor<?>[declaredConstructors.length];
|
||||
|
||||
int sz = 0;
|
||||
for (TConstructor<?> constructor : declaredConstructors) {
|
||||
if (TModifier.isPublic(constructor.getModifiers())) {
|
||||
constructors[sz++] = constructor;
|
||||
}
|
||||
}
|
||||
|
||||
if (sz < constructors.length) {
|
||||
constructors = Arrays.copyOf(constructors, sz);
|
||||
}
|
||||
|
||||
return constructors;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "raw", "unchecked" })
|
||||
public TConstructor<T> getDeclaredConstructor(TClass<?>... parameterTypes)
|
||||
throws TSecurityException, TNoSuchMethodException {
|
||||
for (TConstructor<?> constructor : getDeclaredConstructors()) {
|
||||
if (Arrays.equals(constructor.getParameterTypes(), parameterTypes)) {
|
||||
return (TConstructor<T>) constructor;
|
||||
}
|
||||
}
|
||||
throw new TNoSuchMethodException();
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "raw", "unchecked" })
|
||||
public TConstructor<T> getConstructor(TClass<?>... parameterTypes)
|
||||
throws TSecurityException, TNoSuchMethodException {
|
||||
for (TConstructor<?> constructor : getDeclaredConstructors()) {
|
||||
if (TModifier.isPublic(constructor.getModifiers())
|
||||
&& Arrays.equals(constructor.getParameterTypes(), parameterTypes)) {
|
||||
return (TConstructor<T>) constructor;
|
||||
}
|
||||
}
|
||||
throw new TNoSuchMethodException();
|
||||
}
|
||||
|
||||
private static void getFieldsOfInterfaces(TClass<?> iface, List<TField> fields, Set<TClass<?>> visited) {
|
||||
if (!visited.add(iface)) {
|
||||
return;
|
||||
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* 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 org.teavm.classlib.java.lang;
|
||||
|
||||
public class TNoSuchMethodException extends TReflectiveOperationException {
|
||||
public TNoSuchMethodException() {
|
||||
}
|
||||
|
||||
public TNoSuchMethodException(TString message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
@ -103,7 +103,8 @@ public class TConstructor<T> extends TAccessibleObject implements TMember {
|
||||
throw new TIllegalArgumentException();
|
||||
}
|
||||
for (int i = 0; i < initargs.length; ++i) {
|
||||
if (initargs[i] != null && !parameterTypes[i].isInstance((TObject) initargs[i])) {
|
||||
if (!parameterTypes[i].isPrimitive() && initargs[i] != null
|
||||
&& !parameterTypes[i].isInstance((TObject) initargs[i])) {
|
||||
throw new TIllegalArgumentException();
|
||||
}
|
||||
if (parameterTypes[i].isPrimitive() && initargs[i] == null) {
|
||||
@ -112,7 +113,8 @@ public class TConstructor<T> extends TAccessibleObject implements TMember {
|
||||
}
|
||||
|
||||
PlatformSequence<PlatformObject> jsArgs = Converter.arrayFromJava(initargs);
|
||||
PlatformObject instance = callable.call(null, jsArgs);
|
||||
PlatformObject instance = declaringClass.newEmptyInstance();
|
||||
callable.call(instance, jsArgs);
|
||||
return (T) Converter.toJava(instance);
|
||||
}
|
||||
|
||||
|
45
samples/kotlin/teavm-samples-kotlin.iml
Normal file
45
samples/kotlin/teavm-samples-kotlin.iml
Normal file
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="web" name="Web">
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<deploymentDescriptor name="web.xml" url="file://$MODULE_DIR$/src/main/webapp/WEB-INF/web.xml" />
|
||||
</descriptors>
|
||||
<webroots>
|
||||
<root url="file://$MODULE_DIR$/target/generated/js" relative="/" />
|
||||
<root url="file://$MODULE_DIR$/src/main/webapp" relative="/" />
|
||||
</webroots>
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="false">
|
||||
<output url="file://$MODULE_DIR$/target/classes" />
|
||||
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/kotlin" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: org.jetbrains.kotlin:kotlin-stdlib:1.0.3" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: org.jetbrains.kotlin:kotlin-runtime:1.0.3" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.11" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
|
||||
<orderEntry type="module" module-name="teavm-classlib" scope="PROVIDED" />
|
||||
<orderEntry type="module" module-name="teavm-platform" scope="PROVIDED" />
|
||||
<orderEntry type="module" module-name="teavm-core" scope="PROVIDED" />
|
||||
<orderEntry type="module" module-name="teavm-interop" scope="PROVIDED" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: commons-io:commons-io:2.4" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: com.carrotsearch:hppc:0.6.1" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: org.objenesis:objenesis:2.4" level="project" />
|
||||
<orderEntry type="module" module-name="teavm-jso" scope="PROVIDED" />
|
||||
<orderEntry type="module" module-name="teavm-jso-impl" scope="PROVIDED" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: org.mozilla:rhino:1.7.7" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: org.ow2.asm:asm-debug-all:5.0.4" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: com.google.code.gson:gson:2.2.4" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: com.jcraft:jzlib:1.1.3" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: joda-time:joda-time:2.7" level="project" />
|
||||
<orderEntry type="module" module-name="teavm-jso-apis" scope="PROVIDED" />
|
||||
</component>
|
||||
</module>
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2016 Alexey Andreev.
|
||||
*
|
||||
* 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 org.teavm.classlib.java.lang.reflect;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.teavm.classlib.support.Reflectable;
|
||||
import org.teavm.junit.TeaVMTestRunner;
|
||||
|
||||
@RunWith(TeaVMTestRunner.class)
|
||||
public class ConstructorTest {
|
||||
@Test
|
||||
public void constructorsEnumerated() {
|
||||
callConstructors();
|
||||
|
||||
assertEquals(""
|
||||
+ "ConstructorTest$ReflectableType(int,java.lang.Object);"
|
||||
+ "ConstructorTest$ReflectableType(java.lang.String);"
|
||||
+ "protected ConstructorTest$ReflectableType();"
|
||||
+ "public ConstructorTest$ReflectableType(int);",
|
||||
collectConstructors(ReflectableType.class.getDeclaredConstructors()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void publicConstructorsEnumerated() {
|
||||
callConstructors();
|
||||
|
||||
assertEquals("public ConstructorTest$ReflectableType(int);",
|
||||
collectConstructors(ReflectableType.class.getConstructors()));
|
||||
}
|
||||
|
||||
private void callConstructors() {
|
||||
new ReflectableType();
|
||||
new ReflectableType(1);
|
||||
new ReflectableType("2");
|
||||
new ReflectableType(1, "2");
|
||||
}
|
||||
|
||||
private String collectConstructors(Constructor<?>[] constructors) {
|
||||
List<String> lines = new ArrayList<>();
|
||||
for (Constructor<?> constructor : constructors) {
|
||||
lines.add(constructor + ";");
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Collections.sort(lines);
|
||||
for (String line : lines) {
|
||||
sb.append(line);
|
||||
}
|
||||
return sb.toString().replace("org.teavm.classlib.java.lang.reflect.", "");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newInstance() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
|
||||
InstantiationException {
|
||||
Constructor<ReflectableType> constructor = ReflectableType.class.getDeclaredConstructor();
|
||||
ReflectableType instance = constructor.newInstance();
|
||||
assertEquals(0, instance.a);
|
||||
assertNull(instance.b);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void newInstance2() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
|
||||
InstantiationException {
|
||||
Constructor<ReflectableType> constructor = ReflectableType.class
|
||||
.getDeclaredConstructor(int.class, Object.class);
|
||||
ReflectableType instance = constructor.newInstance(23, "42");
|
||||
assertEquals(23, instance.a);
|
||||
assertEquals("42", instance.b);
|
||||
}
|
||||
|
||||
static class ReflectableType {
|
||||
public int a;
|
||||
public Object b;
|
||||
|
||||
@Reflectable protected ReflectableType() {
|
||||
}
|
||||
|
||||
@Reflectable public ReflectableType(int a) {
|
||||
this.a = a;
|
||||
}
|
||||
|
||||
@Reflectable ReflectableType(String b) {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
@Reflectable ReflectableType(int a, Object b) {
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
}
|
||||
}
|
||||
}
|
@ -302,6 +302,8 @@ public class TeaVMTestRunner extends Runner implements Filterable {
|
||||
compileResult = compileTest(child, configuration);
|
||||
} catch (Exception e) {
|
||||
notifier.fireTestFailure(new Failure(description, e));
|
||||
notifier.fireTestFinished(description);
|
||||
latch.countDown();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user