use of org.objectweb.asm.commons.Method in project cdap by caskdata.
the class AuthEnforceRewriter method rewriteClass.
@Override
public byte[] rewriteClass(String className, InputStream input) throws IOException {
byte[] classBytes = ByteStreams.toByteArray(input);
// First pass: Check the class to have a method with AuthEnforce annotation if found store the annotation details
// and parameters for the method for second pass in which class rewrite will be performed.
ClassReader cr = new ClassReader(classBytes);
// SKIP_CODE SKIP_DEBUG and SKIP_FRAMESto make the first pass faster since in the first pass we just want to
// process annotations to check if the class has any method with AuthEnforce annotation. If such method is found
// we also store the parameters which has the named annotations as specified in the entities field of the
// AuthEnforce.
AuthEnforceAnnotationVisitor classVisitor = new AuthEnforceAnnotationVisitor(className);
cr.accept(classVisitor, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
Map<Method, AnnotationDetail> methodAnnotations = classVisitor.getMethodAnnotations();
if (methodAnnotations.isEmpty()) {
// if no AuthEnforce annotation was found then return the original class bytes
return classBytes;
}
// We found some method which has AuthEnforce annotation so we need a second pass in to rewrite the class
// in second pass we COMPUTE_FRAMES and visit classes with EXPAND_FRAMES
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
cr.accept(new AuthEnforceAnnotationRewriter(className, cw, classVisitor.getFieldDetails(), methodAnnotations), ClassReader.EXPAND_FRAMES);
return cw.toByteArray();
}
use of org.objectweb.asm.commons.Method in project cdap by caskdata.
the class DatumWriterGenerator method encodeRecord.
/**
* Generates method body for encoding java class. If the class given is an interface,
* getter method will be used to access the field values, otherwise, it will assumes
* fields are public.
*
* @param mg
* @param schema
* @param outputType
* @param value
* @param encoder
* @param schemaLocal
* @param seenRefs
*/
private void encodeRecord(GeneratorAdapter mg, Schema schema, TypeToken<?> outputType, int value, int encoder, int schemaLocal, int seenRefs) {
try {
Class<?> rawType = outputType.getRawType();
// Record type might be defined by the user, hence need to preserve class loading of it
preservedClasses.add(rawType);
boolean isInterface = rawType.isInterface();
/*
Check for circular reference
if (value != null && !seenRefs.add(value)) {
throw new IOException(...);
}
*/
Label notSeen = mg.newLabel();
mg.loadArg(value);
mg.ifNull(notSeen);
mg.loadArg(seenRefs);
mg.loadArg(value);
mg.invokeInterface(Type.getType(Set.class), getMethod(boolean.class, "add", Object.class));
mg.ifZCmp(GeneratorAdapter.NE, notSeen);
mg.throwException(Type.getType(IOException.class), "Circular reference not supported.");
mg.mark(notSeen);
// Store the list of schema fields.
mg.loadArg(schemaLocal);
mg.invokeVirtual(Type.getType(Schema.class), getMethod(List.class, "getFields"));
int fieldSchemas = mg.newLocal(Type.getType(List.class));
mg.storeLocal(fieldSchemas);
// For each field, call the encode method for the field
List<Schema.Field> fields = schema.getFields();
for (int i = 0; i < fields.size(); i++) {
Schema.Field field = fields.get(i);
TypeToken<?> fieldType;
// this.encodeFieldMethod(value.fieldName, encoder, fieldSchemas.get(i).getSchema());
if (isInterface) {
mg.loadThis();
mg.loadArg(value);
Method getter = getGetter(outputType, field.getName());
fieldType = outputType.resolveType(rawType.getMethod(getter.getName()).getGenericReturnType());
mg.invokeInterface(Type.getType(rawType), getter);
} else {
fieldType = outputType.resolveType(Fields.findField(outputType.getType(), field.getName()).getGenericType());
fieldAccessorRequests.put(outputType, field.getName());
mg.loadThis();
mg.dup();
mg.getField(classType, getFieldAccessorName(outputType, field.getName()), Type.getType(FieldAccessor.class));
mg.loadArg(value);
mg.invokeInterface(Type.getType(FieldAccessor.class), getAccessorMethod(fieldType));
if (!fieldType.getRawType().isPrimitive()) {
doCast(mg, fieldType, field.getSchema());
}
}
mg.loadArg(encoder);
mg.loadLocal(fieldSchemas);
mg.push(i);
mg.invokeInterface(Type.getType(List.class), getMethod(Object.class, "get", int.class));
mg.checkCast(Type.getType(Schema.Field.class));
mg.invokeVirtual(Type.getType(Schema.Field.class), getMethod(Schema.class, "getSchema"));
mg.loadArg(seenRefs);
mg.invokeVirtual(classType, getEncodeMethod(fieldType, field.getSchema()));
}
} catch (Exception e) {
throw Throwables.propagate(e);
}
}
use of org.objectweb.asm.commons.Method in project cdap by caskdata.
the class DatumWriterGenerator method generateEncode.
/**
* Generates the {@link DatumWriter#encode(Object, co.cask.cdap.common.io.Encoder)} method.
* @param outputType Type information of the data type for output
* @param schema Schema to use for output.
*/
private void generateEncode(TypeToken<?> outputType, Schema schema) {
TypeToken<?> callOutputType = getCallTypeToken(outputType, schema);
Method encodeMethod = getMethod(void.class, "encode", callOutputType.getRawType(), Encoder.class);
if (!Object.class.equals(callOutputType.getRawType())) {
// Generate the synthetic method for the bridging
Method method = getMethod(void.class, "encode", Object.class, Encoder.class);
GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC + Opcodes.ACC_BRIDGE + Opcodes.ACC_SYNTHETIC, method, null, new Type[] { Type.getType(IOException.class) }, classWriter);
mg.loadThis();
mg.loadArg(0);
mg.checkCast(Type.getType(callOutputType.getRawType()));
mg.loadArg(1);
mg.invokeVirtual(classType, encodeMethod);
mg.returnValue();
mg.endMethod();
}
// Generate the top level public encode method
String methodSignature = null;
if (callOutputType.getType() instanceof ParameterizedType) {
methodSignature = Signatures.getMethodSignature(encodeMethod, TypeToken.of(void.class), callOutputType, null);
}
GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC, encodeMethod, methodSignature, new Type[] { Type.getType(IOException.class) }, classWriter);
// Delegate to the actual encode method(value, encoder, schema, Sets.newIdentityHashSet());
mg.loadThis();
mg.loadArg(0);
mg.loadArg(1);
mg.loadThis();
mg.getField(classType, "schema", Type.getType(Schema.class));
// seenRefs Set
mg.invokeStatic(Type.getType(Sets.class), getMethod(Set.class, "newIdentityHashSet"));
mg.invokeVirtual(classType, getEncodeMethod(outputType, schema));
mg.returnValue();
mg.endMethod();
}
use of org.objectweb.asm.commons.Method in project cdap by caskdata.
the class DatumWriterGenerator method generateConstructor.
/**
* Generates the constructor. The constructor generated has signature {@code (Schema, FieldAccessorFactory)}.
*/
private void generateConstructor() {
Method constructor = getMethod(void.class, "<init>", Schema.class, FieldAccessorFactory.class);
// Constructor(Schema schema, FieldAccessorFactory accessorFactory)
GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PUBLIC, constructor, null, null, classWriter);
// super(); // Calling Object constructor
mg.loadThis();
mg.invokeConstructor(Type.getType(Object.class), getMethod(void.class, "<init>"));
// if (!SCHEMA_HASH.equals(schema.getSchemaHash().toString())) { throw IllegalArgumentException }
mg.getStatic(classType, "SCHEMA_HASH", Type.getType(String.class));
mg.loadArg(0);
mg.invokeVirtual(Type.getType(Schema.class), getMethod(SchemaHash.class, "getSchemaHash"));
mg.invokeVirtual(Type.getType(SchemaHash.class), getMethod(String.class, "toString"));
mg.invokeVirtual(Type.getType(String.class), getMethod(boolean.class, "equals", Object.class));
Label hashEquals = mg.newLabel();
mg.ifZCmp(GeneratorAdapter.NE, hashEquals);
mg.throwException(Type.getType(IllegalArgumentException.class), "Schema not match.");
mg.mark(hashEquals);
// this.schema = schema;
mg.loadThis();
mg.loadArg(0);
mg.putField(classType, "schema", Type.getType(Schema.class));
// For each record field that needs an accessor, get the accessor and store it in field.
for (Map.Entry<TypeToken<?>, String> entry : fieldAccessorRequests.entries()) {
String fieldAccessorName = getFieldAccessorName(entry.getKey(), entry.getValue());
classWriter.visitField(Opcodes.ACC_PRIVATE + Opcodes.ACC_FINAL, fieldAccessorName, Type.getDescriptor(FieldAccessor.class), null, null);
// this.fieldAccessorName
// = accessorFactory.getFieldAccessor(TypeToken.of(Class.forName("className")), "fieldName");
mg.loadThis();
mg.loadArg(1);
mg.push(entry.getKey().getRawType().getName());
mg.invokeStatic(Type.getType(Class.class), getMethod(Class.class, "forName", String.class));
mg.invokeStatic(Type.getType(TypeToken.class), getMethod(TypeToken.class, "of", Class.class));
mg.push(entry.getValue());
mg.invokeInterface(Type.getType(FieldAccessorFactory.class), getMethod(FieldAccessor.class, "getFieldAccessor", TypeToken.class, String.class));
mg.putField(classType, fieldAccessorName, Type.getType(FieldAccessor.class));
}
mg.returnValue();
mg.endMethod();
}
use of org.objectweb.asm.commons.Method in project cdap by caskdata.
the class DatumWriterGenerator method getEncodeMethod.
/**
* Returns the encode method for the given type and schema. The same method will be returned if the same
* type and schema has been passed to the method before.
*
* @param outputType Type information of the data type for output
* @param schema Schema to use for output.
* @return A method for encoding the given output type and schema.
*/
private Method getEncodeMethod(TypeToken<?> outputType, Schema schema) {
String key = String.format("%s%s", normalizeTypeName(outputType), schema.getSchemaHash());
Method method = encodeMethods.get(key);
if (method != null) {
return method;
}
// Generate the encode method (value, encoder, schema, set)
TypeToken<?> callOutputType = getCallTypeToken(outputType, schema);
String methodName = String.format("encode%s", key);
method = getMethod(void.class, methodName, callOutputType.getRawType(), Encoder.class, Schema.class, Set.class);
// Put the method into map first before generating the body in order to support recursive data type.
encodeMethods.put(key, method);
String methodSignature = Signatures.getMethodSignature(method, TypeToken.of(void.class), callOutputType, null, null, new TypeToken<Set<Object>>() {
});
GeneratorAdapter mg = new GeneratorAdapter(Opcodes.ACC_PRIVATE, method, methodSignature, new Type[] { Type.getType(IOException.class) }, classWriter);
generateEncodeBody(mg, schema, outputType, 0, 1, 2, 3);
mg.returnValue();
mg.endMethod();
return method;
}
Aggregations