Implement metaprogramming proxies

This commit is contained in:
Alexey Andreev 2016-04-06 23:02:15 +03:00
parent b0e9f6f7a5
commit 84d9899b3e
8 changed files with 378 additions and 5 deletions

View File

@ -14,7 +14,7 @@
<property key="Bundle-Description" value="TeaVM Java class library emulation" /> <property key="Bundle-Description" value="TeaVM Java class library emulation" />
<property key="Export-Package" value="org.teavm.classlib.*" /> <property key="Export-Package" value="org.teavm.classlib.*" />
<property key="Bundle-Name" value="TeaVM Java class library" /> <property key="Bundle-Name" value="TeaVM Java class library" />
<property key="Include-Resource" value="html/jcl.html=$MODULE_DIR$/src/main/resources/html/jcl.html,html/annotation_obj.png=$MODULE_DIR$/src/main/resources/html/annotation_obj.png,html/enum_obj.png=$MODULE_DIR$/src/main/resources/html/enum_obj.png,html/jcl.css=$MODULE_DIR$/src/main/resources/html/jcl.css,html/package_obj.png=$MODULE_DIR$/src/main/resources/html/package_obj.png,html/field_public_obj.png=$MODULE_DIR$/src/main/resources/html/field_public_obj.png,html/class_obj.png=$MODULE_DIR$/src/main/resources/html/class_obj.png,html/int_obj.png=$MODULE_DIR$/src/main/resources/html/int_obj.png,html/jcl-class.html=$MODULE_DIR$/src/main/resources/html/jcl-class.html,html/methpro_obj.png=$MODULE_DIR$/src/main/resources/html/methpro_obj.png,html/methpub_obj.png=$MODULE_DIR$/src/main/resources/html/methpub_obj.png,html/field_protected_obj.png=$MODULE_DIR$/src/main/resources/html/field_protected_obj.png,META-INF/teavm.properties=$MODULE_DIR$/src/main/resources/META-INF/teavm.properties,META-INF/services/org.teavm.vm.spi.TeaVMPlugin=$MODULE_DIR$/src/main/resources/META-INF/services/org.teavm.vm.spi.TeaVMPlugin,org/teavm/classlib/impl/tz/tzdata2015d.zip=$MODULE_DIR$/src/main/resources/org/teavm/classlib/impl/tz/tzdata2015d.zip,org/teavm/classlib/impl/currency/iso4217.xml=$MODULE_DIR$/src/main/resources/org/teavm/classlib/impl/currency/iso4217.xml,org/teavm/classlib/impl/currency/iso3166.csv=$MODULE_DIR$/src/main/resources/org/teavm/classlib/impl/currency/iso3166.csv,org/teavm/classlib/impl/unicode/UnicodeData.txt=$MODULE_DIR$/src/main/resources/org/teavm/classlib/impl/unicode/UnicodeData.txt,org/teavm/classlib/impl/unicode/cldr-json.zip=$MODULE_DIR$/src/main/resources/org/teavm/classlib/impl/unicode/cldr-json.zip" /> <property key="Include-Resource" value="META-INF/services/org.teavm.vm.spi.TeaVMPlugin=$MODULE_DIR$/src/main/resources/META-INF/services/org.teavm.vm.spi.TeaVMPlugin,META-INF/teavm.properties=$MODULE_DIR$/src/main/resources/META-INF/teavm.properties,html/field_public_obj.png=$MODULE_DIR$/src/main/resources/html/field_public_obj.png,html/methpro_obj.png=$MODULE_DIR$/src/main/resources/html/methpro_obj.png,html/int_obj.png=$MODULE_DIR$/src/main/resources/html/int_obj.png,html/jcl-class.html=$MODULE_DIR$/src/main/resources/html/jcl-class.html,html/enum_obj.png=$MODULE_DIR$/src/main/resources/html/enum_obj.png,html/jcl.css=$MODULE_DIR$/src/main/resources/html/jcl.css,html/field_protected_obj.png=$MODULE_DIR$/src/main/resources/html/field_protected_obj.png,html/class_obj.png=$MODULE_DIR$/src/main/resources/html/class_obj.png,html/package_obj.png=$MODULE_DIR$/src/main/resources/html/package_obj.png,html/methpub_obj.png=$MODULE_DIR$/src/main/resources/html/methpub_obj.png,html/annotation_obj.png=$MODULE_DIR$/src/main/resources/html/annotation_obj.png,html/jcl.html=$MODULE_DIR$/src/main/resources/html/jcl.html,org/teavm/classlib/impl/currency/iso4217.xml=$MODULE_DIR$/src/main/resources/org/teavm/classlib/impl/currency/iso4217.xml,org/teavm/classlib/impl/currency/iso3166.csv=$MODULE_DIR$/src/main/resources/org/teavm/classlib/impl/currency/iso3166.csv,org/teavm/classlib/impl/unicode/UnicodeData.txt=$MODULE_DIR$/src/main/resources/org/teavm/classlib/impl/unicode/UnicodeData.txt,org/teavm/classlib/impl/unicode/cldr-json.zip=$MODULE_DIR$/src/main/resources/org/teavm/classlib/impl/unicode/cldr-json.zip,org/teavm/classlib/impl/tz/tzdata2015d.zip=$MODULE_DIR$/src/main/resources/org/teavm/classlib/impl/tz/tzdata2015d.zip" />
</additionalProperties> </additionalProperties>
<additionalJARContents /> <additionalJARContents />
</configuration> </configuration>

View File

@ -15,6 +15,8 @@
*/ */
package org.teavm.metaprogramming.impl; package org.teavm.metaprogramming.impl;
import java.util.HashMap;
import java.util.Map;
import org.teavm.dependency.DependencyAgent; import org.teavm.dependency.DependencyAgent;
import org.teavm.metaprogramming.Action; import org.teavm.metaprogramming.Action;
import org.teavm.metaprogramming.Computation; import org.teavm.metaprogramming.Computation;
@ -28,14 +30,19 @@ import org.teavm.metaprogramming.impl.reflect.ReflectClassImpl;
import org.teavm.metaprogramming.impl.reflect.ReflectContext; import org.teavm.metaprogramming.impl.reflect.ReflectContext;
import org.teavm.metaprogramming.impl.reflect.ReflectFieldImpl; import org.teavm.metaprogramming.impl.reflect.ReflectFieldImpl;
import org.teavm.metaprogramming.impl.reflect.ReflectMethodImpl; import org.teavm.metaprogramming.impl.reflect.ReflectMethodImpl;
import org.teavm.metaprogramming.reflect.ReflectMethod;
import org.teavm.model.AccessLevel;
import org.teavm.model.BasicBlock; import org.teavm.model.BasicBlock;
import org.teavm.model.CallLocation; import org.teavm.model.CallLocation;
import org.teavm.model.ClassHolder; import org.teavm.model.ClassHolder;
import org.teavm.model.ClassReaderSource; import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementModifier;
import org.teavm.model.Instruction; import org.teavm.model.Instruction;
import org.teavm.model.InstructionLocation; import org.teavm.model.InstructionLocation;
import org.teavm.model.MethodHolder;
import org.teavm.model.MethodReader; import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference; import org.teavm.model.MethodReference;
import org.teavm.model.Program;
import org.teavm.model.ValueType; import org.teavm.model.ValueType;
import org.teavm.model.Variable; import org.teavm.model.Variable;
import org.teavm.model.instructions.DoubleConstantInstruction; import org.teavm.model.instructions.DoubleConstantInstruction;
@ -44,11 +51,13 @@ import org.teavm.model.instructions.FloatConstantInstruction;
import org.teavm.model.instructions.IntegerConstantInstruction; import org.teavm.model.instructions.IntegerConstantInstruction;
import org.teavm.model.instructions.InvocationType; import org.teavm.model.instructions.InvocationType;
import org.teavm.model.instructions.InvokeInstruction; import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.instructions.JumpInstruction;
import org.teavm.model.instructions.LongConstantInstruction; import org.teavm.model.instructions.LongConstantInstruction;
import org.teavm.model.instructions.NullConstantInstruction; import org.teavm.model.instructions.NullConstantInstruction;
import org.teavm.model.util.InstructionTransitionExtractor; import org.teavm.model.util.InstructionTransitionExtractor;
public final class MetaprogrammingImpl { public final class MetaprogrammingImpl {
static Map<String, Integer> proxySuffixGenerators = new HashMap<>();
static ClassLoader classLoader; static ClassLoader classLoader;
static ClassReaderSource classSource; static ClassReaderSource classSource;
static ReflectContext reflectContext; static ReflectContext reflectContext;
@ -207,8 +216,86 @@ public final class MetaprogrammingImpl {
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public static <T> Value<T> proxy(ReflectClass<T> type, InvocationHandler<T> handler) { public static <T> Value<T> proxy(ReflectClass<T> type, InvocationHandler<T> handler) {
unsupported(); ValueType innerType = ((ReflectClassImpl<?>) type).type;
return null; ClassHolder cls = new ClassHolder(createProxyName(type.getName()));
cls.setLevel(AccessLevel.PUBLIC);
String typeName = ((ValueType.Object) innerType).getClassName();
org.teavm.model.ClassReader typeReader = classSource.get(typeName);
if (typeReader.hasModifier(ElementModifier.INTERFACE)) {
cls.setParent("java.lang.Object");
cls.getInterfaces().add(typeName);
} else {
cls.setParent(typeName);
}
ProxyVariableContext nestedVarContext = new ProxyVariableContext(varContext, cls);
for (ReflectMethod method : type.getMethods()) {
ReflectMethodImpl methodImpl = (ReflectMethodImpl) method;
if (methodImpl.method.getProgram() != null && methodImpl.method.getProgram().basicBlockCount() > 0
|| methodImpl.method.hasModifier(ElementModifier.NATIVE)
|| !methodImpl.method.hasModifier(ElementModifier.ABSTRACT)) {
continue;
}
MethodHolder methodHolder = new MethodHolder(methodImpl.method.getDescriptor());
methodHolder.setLevel(AccessLevel.PUBLIC);
ValueType returnTypeBackup = returnType;
VariableContext varContextBackup = varContext;
CompositeMethodGenerator generatorBackup = generator;
try {
returnType = methodHolder.getResultType();
varContext = nestedVarContext;
generator = new CompositeMethodGenerator(varContext, new Program());
Program program = generator.program;
program.createBasicBlock();
generator.blockIndex = 0;
BasicBlock startBlock = generator.currentBlock();
nestedVarContext.init(startBlock);
methodHolder.setProgram(program);
Variable thisVar = program.createVariable();
int argumentCount = methodImpl.method.parameterCount();
@SuppressWarnings("unchecked")
ValueImpl<Object>[] arguments = (ValueImpl<Object>[]) new ValueImpl<?>[argumentCount];
for (int i = 0; i < arguments.length; ++i) {
arguments[i] = new ValueImpl<>(program.createVariable(), nestedVarContext,
methodImpl.method.parameterType(i));
}
for (int i = 0; i < arguments.length; ++i) {
ValueType argType = methodImpl.method.parameterType(i);
Variable var = generator.box(arguments[i].innerValue, argType);
arguments[i] = new ValueImpl<>(var, nestedVarContext, argType);
}
handler.invoke(new ValueImpl<>(thisVar, nestedVarContext, innerType), methodImpl, arguments);
close();
JumpInstruction jumpToStart = new JumpInstruction();
jumpToStart.setTarget(program.basicBlockAt(startBlock.getIndex() + 1));
startBlock.getInstructions().add(jumpToStart);
//new BoxingEliminator().optimize(program);
cls.addMethod(methodHolder);
} finally {
returnType = returnTypeBackup;
varContext = varContextBackup;
generator = generatorBackup;
}
}
ValueImpl<T> result = new ValueImpl<>(nestedVarContext.createInstance(generator), varContext, innerType);
agent.submitClass(cls);
return result;
}
private static String createProxyName(String className) {
int suffix = proxySuffixGenerators.getOrDefault(className, 0);
proxySuffixGenerators.put(className, suffix + 1);
return className + "$proxy" + suffix;
} }
private static void returnValue(Variable var) { private static void returnValue(Variable var) {

View File

@ -0,0 +1,150 @@
/*
* 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.metaprogramming.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.teavm.model.AccessLevel;
import org.teavm.model.BasicBlock;
import org.teavm.model.CallLocation;
import org.teavm.model.ClassHolder;
import org.teavm.model.FieldHolder;
import org.teavm.model.MethodHolder;
import org.teavm.model.MethodReference;
import org.teavm.model.Program;
import org.teavm.model.ValueType;
import org.teavm.model.Variable;
import org.teavm.model.instructions.ConstructInstruction;
import org.teavm.model.instructions.ExitInstruction;
import org.teavm.model.instructions.GetFieldInstruction;
import org.teavm.model.instructions.InvocationType;
import org.teavm.model.instructions.InvokeInstruction;
import org.teavm.model.instructions.PutFieldInstruction;
public class ProxyVariableContext extends VariableContext {
private Map<ValueImpl<?>, Variable> cache = new HashMap<>();
private BasicBlock startBlock;
private ClassHolder proxyClass;
private int suffixGenerator;
private Map<Variable, CapturedValue> capturedValueMap = new HashMap<>();
private List<CapturedValue> capturedValues = new ArrayList<>();
public ProxyVariableContext(VariableContext parent, ClassHolder proxyClass) {
super(parent);
this.proxyClass = proxyClass;
}
public void init(BasicBlock startBlock) {
this.startBlock = startBlock;
cache.clear();
}
@Override
public Variable emitVariable(ValueImpl<?> value, CallLocation location) {
return cache.computeIfAbsent(value, v -> createVariable(v, location));
}
private Variable createVariable(ValueImpl<?> value, CallLocation location) {
if (value.context == this) {
return value.innerValue;
}
Variable outerVar = getParent().emitVariable(value, location);
CapturedValue capturedValue = capturedValueMap.computeIfAbsent(outerVar, v -> {
FieldHolder field = new FieldHolder("proxyCapture" + suffixGenerator++);
field.setLevel(AccessLevel.PUBLIC);
field.setType(value.type);
proxyClass.addField(field);
CapturedValue result = new CapturedValue(field, v);
capturedValues.add(result);
return result;
});
Program program = startBlock.getProgram();
Variable var = program.createVariable();
GetFieldInstruction insn = new GetFieldInstruction();
insn.setInstance(program.variableAt(0));
insn.setField(capturedValue.field.getReference());
insn.setFieldType(capturedValue.field.getType());
insn.setReceiver(var);
startBlock.getInstructions().add(insn);
return var;
}
public Variable createInstance(CompositeMethodGenerator generator) {
ValueType[] signature = new ValueType[capturedValues.size() + 1];
for (int i = 0; i < capturedValues.size(); ++i) {
signature[i] = capturedValues.get(i).field.getType();
}
signature[capturedValues.size()] = ValueType.VOID;
MethodHolder ctor = new MethodHolder("<init>", signature);
ctor.setLevel(AccessLevel.PUBLIC);
Program ctorProgram = new Program();
ctor.setProgram(ctorProgram);
BasicBlock ctorBlock = ctorProgram.createBasicBlock();
InvokeInstruction invokeSuper = new InvokeInstruction();
invokeSuper.setInstance(ctorProgram.createVariable());
invokeSuper.setMethod(new MethodReference(proxyClass.getParent(), "<init>", ValueType.VOID));
invokeSuper.setType(InvocationType.SPECIAL);
ctorBlock.getInstructions().add(invokeSuper);
for (int i = 0; i < capturedValues.size(); ++i) {
PutFieldInstruction putInsn = new PutFieldInstruction();
putInsn.setField(capturedValues.get(i).field.getReference());
putInsn.setFieldType(capturedValues.get(i).field.getType());
putInsn.setValue(ctorProgram.createVariable());
putInsn.setInstance(ctorProgram.variableAt(0));
ctorBlock.getInstructions().add(putInsn);
}
ExitInstruction exit = new ExitInstruction();
ctorBlock.getInstructions().add(exit);
proxyClass.addMethod(ctor);
ConstructInstruction constructInsn = new ConstructInstruction();
constructInsn.setReceiver(generator.program.createVariable());
constructInsn.setType(proxyClass.getName());
generator.add(constructInsn);
InvokeInstruction initInsn = new InvokeInstruction();
initInsn.setInstance(constructInsn.getReceiver());
initInsn.setMethod(ctor.getReference());
initInsn.setType(InvocationType.SPECIAL);
for (int i = 0; i < capturedValues.size(); ++i) {
initInsn.getArguments().add(capturedValues.get(i).value);
}
generator.add(initInsn);
return constructInsn.getReceiver();
}
class CapturedValue {
FieldHolder field;
Variable value;
CapturedValue(FieldHolder field, Variable value) {
this.field = field;
this.value = value;
}
}
}

View File

@ -18,5 +18,5 @@ package org.teavm.metaprogramming;
import org.teavm.metaprogramming.reflect.ReflectMethod; import org.teavm.metaprogramming.reflect.ReflectMethod;
public interface InvocationHandler<T> { public interface InvocationHandler<T> {
Computation<?> invoke(Value<T> proxy, ReflectMethod method, Value<Object>[] args); void invoke(Value<T> proxy, ReflectMethod method, Value<Object>[] args);
} }

View File

@ -0,0 +1,120 @@
/*
* 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.metaprogramming.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.teavm.metaprogramming.Metaprogramming.emit;
import static org.teavm.metaprogramming.Metaprogramming.exit;
import static org.teavm.metaprogramming.Metaprogramming.proxy;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.teavm.classlib.java.lang.StringBuilderTest;
import org.teavm.junit.SkipJVM;
import org.teavm.junit.TeaVMTestRunner;
import org.teavm.metaprogramming.CompileTime;
import org.teavm.metaprogramming.Meta;
import org.teavm.metaprogramming.ReflectClass;
import org.teavm.metaprogramming.Value;
@CompileTime
@RunWith(TeaVMTestRunner.class)
@SkipJVM
public class ProxyTest {
@Test
public void createsProxy() {
A proxy = createProxy(A.class, "!");
assertEquals("foo!", proxy.foo());
assertEquals("bar!", proxy.bar());
}
@Meta
private static native <T> T createProxy(Class<T> proxyType, String add);
private static <T> void createProxy(ReflectClass<T> proxyType, Value<String> add) {
Value<T> proxy = proxy(proxyType, (instance, method, args) -> {
String name = method.getName();
exit(() -> name + add.get());
});
exit(() -> proxy.get());
}
@Test
public void defaultReturnValue() {
StringBuilder log = new StringBuilder();
B proxy = createProxyWithDefaultReturnValue(B.class, log);
assertNull(proxy.foo());
assertEquals(0, proxy.bar());
proxy.baz();
assertEquals("foo;bar;baz;", log.toString());
}
@Meta
private static native <T> T createProxyWithDefaultReturnValue(Class<T> proxyType, StringBuilder sb);
private static <T> void createProxyWithDefaultReturnValue(ReflectClass<T> proxyType, Value<StringBuilder> sb) {
Value<T> proxy = proxy(proxyType, (instance, method, args) -> {
String name = method.getName();
emit(() -> sb.get().append(name + ";"));
});
exit(() -> proxy.get());
}
@Test
public void boxParameters() {
C proxy = createProxyWithBoxedParameters(C.class);
assertEquals("foo(true,0,1,2,3,4,5)", proxy.foo(true, (byte) 0, '1', (short) 2, 3, 4, "5"));
}
@Meta
private static native <T> T createProxyWithBoxedParameters(Class<T> proxyType);
private static <T> void createProxyWithBoxedParameters(ReflectClass<T> proxyType) {
Value<T> proxy = proxy(proxyType, (instance, method, args) -> {
Value<StringBuilder> result = emit(() -> new StringBuilder());
String name = method.getName();
emit(() -> result.get().append(name).append('('));
if (args.length > 0) {
emit(() -> result.get().append(args[0].get().toString()));
for (int i = 1; i < args.length; ++i) {
Value<Object> arg = args[i];
emit(() -> result.get().append(',').append(arg.get().toString()));
}
}
emit(() -> result.get().append(')'));
exit(() -> result.get().toString());
});
exit(() -> proxy.get());
}
interface A {
String foo();
String bar();
}
interface B {
String foo();
int bar();
void baz();
}
interface C {
String foo(boolean a, byte b, char c, short d, int e, long f, String g);
}
}

View File

@ -10,6 +10,14 @@
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" scope="TEST" name="Maven: net.sourceforge.htmlunit:htmlunit:2.19" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.apache.httpcomponents:httpmime:4.5.1" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: net.sourceforge.cssparser:cssparser:0.9.18" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.eclipse.jetty.websocket:websocket-client:9.2.13.v20150730" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.eclipse.jetty:jetty-util:9.2.13.v20150730" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.eclipse.jetty:jetty-io:9.2.13.v20150730" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.eclipse.jetty.websocket:websocket-common:9.2.13.v20150730" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: org.eclipse.jetty.websocket:websocket-api:9.2.13.v20150730" level="project" />
<orderEntry type="module" module-name="teavm-core" /> <orderEntry type="module" module-name="teavm-core" />
<orderEntry type="module" module-name="teavm-metaprogramming-api" /> <orderEntry type="module" module-name="teavm-metaprogramming-api" />
<orderEntry type="library" name="Maven: commons-io:commons-io:2.4" level="project" /> <orderEntry type="library" name="Maven: commons-io:commons-io:2.4" level="project" />

View File

@ -7,7 +7,7 @@
<property key="Bundle-Description" value="TeaVM API that helps to create tooling" /> <property key="Bundle-Description" value="TeaVM API that helps to create tooling" />
<property key="Export-Package" value="org.teavm.*" /> <property key="Export-Package" value="org.teavm.*" />
<property key="Bundle-Name" value="TeaVM tooling core" /> <property key="Bundle-Name" value="TeaVM tooling core" />
<property key="Include-Resource" value="org/teavm/tooling/main.html=$MODULE_DIR$/src/main/resources/org/teavm/tooling/main.html,org/teavm/tooling/test/junit.html=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/junit.html,org/teavm/tooling/test/junit-client.html=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/junit-client.html,org/teavm/tooling/test/res/junit-support.js=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/junit-support.js,org/teavm/tooling/test/res/control-000-small.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/control-000-small.png,org/teavm/tooling/test/res/package_obj.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/package_obj.png,org/teavm/tooling/test/res/junit-client.js=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/junit-client.js,org/teavm/tooling/test/res/junit.css=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/junit.css,org/teavm/tooling/test/res/tick-small-red.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/tick-small-red.png,org/teavm/tooling/test/res/tick-small.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/tick-small.png,org/teavm/tooling/test/res/class_obj.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/class_obj.png,org/teavm/tooling/test/res/toggle-small.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/toggle-small.png,org/teavm/tooling/test/res/toggle-small-expand.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/toggle-small-expand.png,org/teavm/tooling/test/res/methpub_obj.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/methpub_obj.png" /> <property key="Include-Resource" value="org/teavm/tooling/test/junit.html=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/junit.html,org/teavm/tooling/test/res/junit.css=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/junit.css,org/teavm/tooling/test/res/tick-small.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/tick-small.png,org/teavm/tooling/test/res/tick-small-red.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/tick-small-red.png,org/teavm/tooling/test/res/toggle-small-expand.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/toggle-small-expand.png,org/teavm/tooling/test/res/control-000-small.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/control-000-small.png,org/teavm/tooling/test/res/junit-support.js=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/junit-support.js,org/teavm/tooling/test/res/class_obj.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/class_obj.png,org/teavm/tooling/test/res/package_obj.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/package_obj.png,org/teavm/tooling/test/res/methpub_obj.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/methpub_obj.png,org/teavm/tooling/test/res/junit-client.js=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/junit-client.js,org/teavm/tooling/test/res/toggle-small.png=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/res/toggle-small.png,org/teavm/tooling/test/junit-client.html=$MODULE_DIR$/src/main/resources/org/teavm/tooling/test/junit-client.html,org/teavm/tooling/main.html=$MODULE_DIR$/src/main/resources/org/teavm/tooling/main.html" />
</additionalProperties> </additionalProperties>
<additionalJARContents /> <additionalJARContents />
</configuration> </configuration>

View File

@ -11,6 +11,14 @@
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Maven: net.sourceforge.htmlunit:htmlunit:2.19" level="project" />
<orderEntry type="library" name="Maven: org.apache.httpcomponents:httpmime:4.5.1" level="project" />
<orderEntry type="library" name="Maven: net.sourceforge.cssparser:cssparser:0.9.18" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-client:9.2.13.v20150730" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-util:9.2.13.v20150730" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-io:9.2.13.v20150730" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-common:9.2.13.v20150730" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-api:9.2.13.v20150730" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: junit:junit:4.11" level="project" /> <orderEntry type="library" scope="PROVIDED" name="Maven: junit:junit:4.11" level="project" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" /> <orderEntry type="library" scope="PROVIDED" name="Maven: org.hamcrest:hamcrest-core:1.3" level="project" />
<orderEntry type="module" module-name="teavm-tooling" /> <orderEntry type="module" module-name="teavm-tooling" />