mirror of
https://github.com/konsoletyper/teavm.git
synced 2025-02-11 11:09:44 +08:00
Add generator of method that reads annotations of a class
This commit is contained in:
parent
c38c07becc
commit
3cb39b9507
@ -16,6 +16,8 @@
|
||||
package org.teavm.classlib.java.lang;
|
||||
|
||||
import org.teavm.classlib.impl.DeclaringClassMetadataGenerator;
|
||||
import org.teavm.classlib.java.lang.annotation.TAnnotation;
|
||||
import org.teavm.classlib.java.lang.reflect.TAnnotatedElement;
|
||||
import org.teavm.platform.Platform;
|
||||
import org.teavm.platform.PlatformClass;
|
||||
import org.teavm.platform.metadata.ClassResource;
|
||||
@ -26,7 +28,7 @@ import org.teavm.platform.metadata.ClassScopedMetadataProvider;
|
||||
* @author Alexey Andreev
|
||||
* @param <T> class type.
|
||||
*/
|
||||
public class TClass<T> extends TObject {
|
||||
public class TClass<T> extends TObject implements TAnnotatedElement {
|
||||
TString name;
|
||||
private TClass<?> componentType;
|
||||
private boolean componentTypeDirty = true;
|
||||
@ -198,4 +200,24 @@ public class TClass<T> extends TObject {
|
||||
}
|
||||
return (TClass<? extends U>)this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAnnotationPresent(TClass<? extends TAnnotation> annotationClass) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S extends TAnnotation> S getAnnotation(TClass<S> annotationClass) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TAnnotation[] getAnnotations() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TAnnotation[] getDeclaredAnnotations() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,213 @@
|
||||
/*
|
||||
* Copyright 2015 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 java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.teavm.dependency.DependencyAgent;
|
||||
import org.teavm.dependency.DependencyListener;
|
||||
import org.teavm.dependency.FieldDependency;
|
||||
import org.teavm.dependency.MethodDependency;
|
||||
import org.teavm.model.AccessLevel;
|
||||
import org.teavm.model.AnnotationReader;
|
||||
import org.teavm.model.AnnotationValue;
|
||||
import org.teavm.model.CallLocation;
|
||||
import org.teavm.model.ClassHolder;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.FieldHolder;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.MethodHolder;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.emit.ProgramEmitter;
|
||||
import org.teavm.model.emit.ValueEmitter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class AnnotationDependencyListener implements DependencyListener {
|
||||
@Override
|
||||
public void started(DependencyAgent agent) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void classAchieved(DependencyAgent agent, String className, CallLocation location) {
|
||||
ClassReader cls = agent.getClassSource().get(className);
|
||||
if (cls == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
MethodHolder readerMethod = new MethodHolder("$$_readAnnotations_$$", ValueType.parse(Annotation[].class));
|
||||
readerMethod.setLevel(AccessLevel.PUBLIC);
|
||||
readerMethod.getModifiers().add(ElementModifier.STATIC);
|
||||
ProgramEmitter pe = ProgramEmitter.create(readerMethod);
|
||||
|
||||
List<AnnotationReader> annotations = new ArrayList<>();
|
||||
for (AnnotationReader annot : cls.getAnnotations().all()) {
|
||||
ClassReader annotType = agent.getClassSource().get(annot.getType());
|
||||
if (annotType == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
AnnotationReader retention = annotType.getAnnotations().get(Retention.class.getName());
|
||||
String retentionPolicy = retention.getValue("value").getEnumValue().getFieldName();
|
||||
if (retentionPolicy.equals("RUNTIME")) {
|
||||
annotations.add(annot);
|
||||
}
|
||||
}
|
||||
|
||||
ValueEmitter array = pe.constructArray(Annotation.class, annotations.size());
|
||||
for (int i = 0; i < annotations.size(); ++i) {
|
||||
array.setElement(i, generateAnnotationInstance(agent, pe, annotations.get(i)));
|
||||
}
|
||||
|
||||
array.returnValue();
|
||||
}
|
||||
|
||||
private ValueEmitter generateAnnotationInstance(DependencyAgent agent, ProgramEmitter pe,
|
||||
AnnotationReader annotation) {
|
||||
ClassReader annotationClass = agent.getClassSource().get(annotation.getType());
|
||||
if (annotationClass == null) {
|
||||
return pe.constantNull();
|
||||
}
|
||||
|
||||
String className = getAnnotationImplementor(agent, annotation.getType());
|
||||
List<ValueType> ctorSignature = new ArrayList<>();
|
||||
List<ValueEmitter> params = new ArrayList<>();
|
||||
for (MethodReader methodDecl : annotationClass.getMethods()) {
|
||||
ctorSignature.add(methodDecl.getResultType());
|
||||
AnnotationValue value = annotation.getValue(className);
|
||||
params.add(value != null ? generateAnnotationValue(agent, pe, methodDecl.getResultType(), value) :
|
||||
pe.constantNull());
|
||||
}
|
||||
ctorSignature.add(ValueType.VOID);
|
||||
|
||||
MethodReference ctor = new MethodReference(className, "<init>", ctorSignature.toArray(
|
||||
new ValueType[ctorSignature.size()]));
|
||||
return pe.construct(ctor, params.toArray(new ValueEmitter[params.size()]));
|
||||
}
|
||||
|
||||
private ValueEmitter generateAnnotationValue(DependencyAgent agent, ProgramEmitter pe, ValueType type,
|
||||
AnnotationValue value) {
|
||||
switch (value.getType()) {
|
||||
case AnnotationValue.BOOLEAN:
|
||||
return pe.constant(value.getBoolean() ? 1 : 0);
|
||||
case AnnotationValue.BYTE:
|
||||
return pe.constant(value.getByte());
|
||||
case AnnotationValue.SHORT:
|
||||
return pe.constant(value.getShort());
|
||||
case AnnotationValue.INT:
|
||||
return pe.constant(value.getInt());
|
||||
case AnnotationValue.LONG:
|
||||
return pe.constant(value.getLong());
|
||||
case AnnotationValue.FLOAT:
|
||||
return pe.constant(value.getFloat());
|
||||
case AnnotationValue.DOUBLE:
|
||||
return pe.constant(value.getDouble());
|
||||
case AnnotationValue.STRING:
|
||||
return pe.constant(value.getString());
|
||||
case AnnotationValue.LIST: {
|
||||
List<AnnotationValue> list = value.getList();
|
||||
ValueType itemType = ((ValueType.Array)type).getItemType();
|
||||
ValueEmitter array = pe.constructArray(itemType, list.size());
|
||||
for (int i = 0; i < list.size(); ++i) {
|
||||
array.setElement(i, generateAnnotationValue(agent, pe, itemType, list.get(i)));
|
||||
}
|
||||
return array;
|
||||
}
|
||||
case AnnotationValue.ENUM:
|
||||
return pe.getField(value.getEnumValue(), type);
|
||||
case AnnotationValue.CLASS:
|
||||
return pe.constant(value.getJavaClass());
|
||||
case AnnotationValue.ANNOTATION:
|
||||
return generateAnnotationInstance(agent, pe, value.getAnnotation());
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown annotation value type: " + value.getType());
|
||||
}
|
||||
}
|
||||
|
||||
private String getAnnotationImplementor(DependencyAgent agent, String annotationType) {
|
||||
String implementorName = annotationType + "$$_impl";
|
||||
if (agent.getClassSource().get(implementorName) == null) {
|
||||
ClassHolder implementor = createImplementor(agent.getClassSource(), annotationType, implementorName);
|
||||
agent.submitClass(implementor);
|
||||
}
|
||||
return implementorName;
|
||||
}
|
||||
|
||||
private ClassHolder createImplementor(ClassReaderSource classSource, String annotationType,
|
||||
String implementorName) {
|
||||
ClassHolder implementor = new ClassHolder(implementorName);
|
||||
implementor.setParent("java.lang.Object");
|
||||
implementor.getInterfaces().add(annotationType);
|
||||
implementor.getModifiers().add(ElementModifier.FINAL);
|
||||
implementor.setLevel(AccessLevel.PUBLIC);
|
||||
|
||||
ClassReader annotation = classSource.get(annotationType);
|
||||
if (annotation == null) {
|
||||
return implementor;
|
||||
}
|
||||
|
||||
List<ValueType> ctorSignature = new ArrayList<>();
|
||||
for (MethodReader methodDecl : annotation.getMethods()) {
|
||||
FieldHolder field = new FieldHolder("$" + methodDecl.getName());
|
||||
field.setType(methodDecl.getResultType());
|
||||
field.setLevel(AccessLevel.PRIVATE);
|
||||
implementor.addField(field);
|
||||
|
||||
MethodHolder accessor = new MethodHolder(methodDecl.getDescriptor());
|
||||
ProgramEmitter pe = ProgramEmitter.create(accessor);
|
||||
ValueEmitter thisVal = pe.wrapNew();
|
||||
ValueEmitter result = thisVal.getField(field.getReference(), field.getType());
|
||||
if (field.getType() instanceof ValueType.Array) {
|
||||
result = result.cloneArray();
|
||||
}
|
||||
result.returnValue();
|
||||
implementor.addMethod(accessor);
|
||||
|
||||
ctorSignature.add(field.getType());
|
||||
}
|
||||
ctorSignature.add(ValueType.VOID);
|
||||
|
||||
MethodHolder ctor = new MethodHolder("<init>", ctorSignature.toArray(new ValueType[ctorSignature.size()]));
|
||||
ProgramEmitter pe = ProgramEmitter.create(ctor);
|
||||
ValueEmitter thisVal = pe.wrapNew();
|
||||
thisVal.invokeSpecial(new MethodReference(Object.class, "<init>", void.class));
|
||||
for (MethodReader methodDecl : annotation.getMethods()) {
|
||||
ValueEmitter param = pe.wrapNew();
|
||||
FieldReference field = new FieldReference(implementorName, "$" + methodDecl.getName());
|
||||
thisVal.setField(field, methodDecl.getResultType(), param);
|
||||
}
|
||||
pe.exit();
|
||||
implementor.addMethod(ctor);
|
||||
|
||||
return implementor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void methodAchieved(DependencyAgent agent, MethodDependency method, CallLocation location) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fieldAchieved(DependencyAgent agent, FieldDependency field, CallLocation location) {
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2015 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 org.teavm.classlib.java.lang.TClass;
|
||||
import org.teavm.classlib.java.lang.annotation.TAnnotation;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public interface TAnnotatedElement {
|
||||
boolean isAnnotationPresent(TClass<? extends TAnnotation> annotationClass);
|
||||
|
||||
<T extends TAnnotation> T getAnnotation(TClass<T> annotationClass);
|
||||
|
||||
TAnnotation[] getAnnotations();
|
||||
|
||||
TAnnotation[] getDeclaredAnnotations();
|
||||
}
|
@ -16,6 +16,8 @@
|
||||
package org.teavm.model.emit;
|
||||
|
||||
import org.teavm.model.*;
|
||||
import org.teavm.model.instructions.ClassConstantInstruction;
|
||||
import org.teavm.model.instructions.ConstructArrayInstruction;
|
||||
import org.teavm.model.instructions.ConstructInstruction;
|
||||
import org.teavm.model.instructions.DoubleConstantInstruction;
|
||||
import org.teavm.model.instructions.ExitInstruction;
|
||||
@ -62,6 +64,19 @@ public final class ProgramEmitter {
|
||||
return block;
|
||||
}
|
||||
|
||||
public ValueEmitter constant(Class<?> cls) {
|
||||
return constant(ValueType.parse(cls));
|
||||
}
|
||||
|
||||
public ValueEmitter constant(ValueType value) {
|
||||
Variable var = program.createVariable();
|
||||
ClassConstantInstruction insn = new ClassConstantInstruction();
|
||||
insn.setReceiver(var);
|
||||
insn.setConstant(value);
|
||||
addInstruction(insn);
|
||||
return wrap(var);
|
||||
}
|
||||
|
||||
public ValueEmitter constant(String value) {
|
||||
Variable var = program.createVariable();
|
||||
StringConstantInstruction insn = new StringConstantInstruction();
|
||||
@ -166,6 +181,28 @@ public final class ProgramEmitter {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public ValueEmitter constructArray(ValueType type, ValueEmitter size) {
|
||||
Variable var = program.createVariable();
|
||||
ConstructArrayInstruction insn = new ConstructArrayInstruction();
|
||||
insn.setReceiver(var);
|
||||
insn.setSize(size.getVariable());
|
||||
insn.setItemType(type);
|
||||
addInstruction(insn);
|
||||
return wrap(var);
|
||||
}
|
||||
|
||||
public ValueEmitter constructArray(ValueType type, int size) {
|
||||
return constructArray(type, constant(size));
|
||||
}
|
||||
|
||||
public ValueEmitter constructArray(Class<?> type, int size) {
|
||||
return constructArray(ValueType.parse(type), size);
|
||||
}
|
||||
|
||||
public ValueEmitter constructArray(Class<?> type, ValueEmitter size) {
|
||||
return constructArray(ValueType.parse(type), size);
|
||||
}
|
||||
|
||||
public ProgramEmitter jump(BasicBlock block) {
|
||||
JumpInstruction insn = new JumpInstruction();
|
||||
insn.setTarget(block);
|
||||
|
@ -33,6 +33,7 @@ import org.teavm.model.instructions.CastInstruction;
|
||||
import org.teavm.model.instructions.CastIntegerDirection;
|
||||
import org.teavm.model.instructions.CastIntegerInstruction;
|
||||
import org.teavm.model.instructions.CastNumberInstruction;
|
||||
import org.teavm.model.instructions.CloneArrayInstruction;
|
||||
import org.teavm.model.instructions.ExitInstruction;
|
||||
import org.teavm.model.instructions.GetElementInstruction;
|
||||
import org.teavm.model.instructions.GetFieldInstruction;
|
||||
@ -42,6 +43,7 @@ import org.teavm.model.instructions.InvokeInstruction;
|
||||
import org.teavm.model.instructions.IsInstanceInstruction;
|
||||
import org.teavm.model.instructions.NegateInstruction;
|
||||
import org.teavm.model.instructions.NumericOperandType;
|
||||
import org.teavm.model.instructions.PutElementInstruction;
|
||||
import org.teavm.model.instructions.PutFieldInstruction;
|
||||
|
||||
/**
|
||||
@ -259,6 +261,22 @@ public class ValueEmitter {
|
||||
return pe.wrap(result);
|
||||
}
|
||||
|
||||
public ValueEmitter getElement(int index) {
|
||||
return getElement(pe.constant(index));
|
||||
}
|
||||
|
||||
public void setElement(ValueEmitter index, ValueEmitter value) {
|
||||
PutElementInstruction insn = new PutElementInstruction();
|
||||
insn.setArray(variable);
|
||||
insn.setIndex(index.variable);
|
||||
insn.setValue(value.variable);
|
||||
pe.addInstruction(insn);
|
||||
}
|
||||
|
||||
public void setElement(int index, ValueEmitter value) {
|
||||
setElement(pe.constant(index), value);
|
||||
}
|
||||
|
||||
public ValueEmitter arrayLength() {
|
||||
Variable result = pe.getProgram().createVariable();
|
||||
ArrayLengthInstruction insn = new ArrayLengthInstruction();
|
||||
@ -277,4 +295,13 @@ public class ValueEmitter {
|
||||
pe.addInstruction(insn);
|
||||
return pe.wrap(result);
|
||||
}
|
||||
|
||||
public ValueEmitter cloneArray() {
|
||||
Variable result = pe.getProgram().createVariable();
|
||||
CloneArrayInstruction insn = new CloneArrayInstruction();
|
||||
insn.setArray(variable);
|
||||
insn.setReceiver(result);
|
||||
pe.addInstruction(insn);
|
||||
return pe.wrap(result);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user