replace also a class with annotation

This commit is contained in:
Volker Berlin 2020-01-03 19:51:58 +01:00
parent 442b582dfc
commit d103f97c04
4 changed files with 101 additions and 13 deletions

View File

@ -34,8 +34,6 @@ import de.inetsoftware.classparser.Attributes.AttributeInfo;
*/
public class ClassFile {
private final DataInputStream input;
private final int minorVersion;
private final int majorVersion;
@ -71,7 +69,7 @@ public class ClassFile {
* if this input stream reaches the end before reading the class file.
*/
public ClassFile( InputStream stream ) throws IOException {
this.input = new DataInputStream( stream );
DataInputStream input = new DataInputStream( stream );
int magic = input.readInt();
if( magic != 0xCAFEBABE ) {
throw new IOException( "Invalid class magic: " + Integer.toHexString( magic ) );
@ -87,8 +85,8 @@ public class ClassFile {
for( int i = 0; i < interfaces.length; i++ ) {
interfaces[i] = (ConstantClass)constantPool.get( input.readUnsignedShort() );
}
fields = readFields();
methods = readMethods();
fields = readFields( input );
methods = readMethods( input );
attributes = new Attributes( input, constantPool );
stream.close();
@ -117,6 +115,45 @@ public class ClassFile {
}
}
/**
* Create a replaced instance.
*
* @param className
* the class name that should be replaced
* @param classFile
* the replacing class file data
*/
public ClassFile( String className, ClassFile classFile ) {
minorVersion = classFile.minorVersion;
majorVersion = classFile.majorVersion;
constantPool = classFile.constantPool;
accessFlags = classFile.accessFlags;
thisClass = new ConstantClass( className );
superClass = classFile.superClass;
interfaces = classFile.interfaces;
fields = classFile.fields;
methods = classFile.methods;
attributes = classFile.attributes;
// patch constant pool
String origClassName = classFile.thisClass.getName();
for( int i = 0; i < constantPool.size(); i++ ) {
Object obj = constantPool.get( i );
if( obj instanceof ConstantClass ) {
if( ((ConstantClass)obj).getName().equals( origClassName ) ) {
constantPool.set( i, thisClass );
}
} else if( obj instanceof ConstantFieldRef ) {
ConstantFieldRef ref = (ConstantFieldRef)obj;
if( ref.getClassName().equals( origClassName ) ) {
ConstantNameAndType nameAndType = new ConstantNameAndType( ref.getName(), ref.getType() );
constantPool.set( i, new ConstantFieldRef( thisClass, nameAndType ) );
}
}
}
}
/**
* Get value of SourceFile if available.
*
@ -216,7 +253,7 @@ public class ClassFile {
return accessFlags;
}
private FieldInfo[] readFields() throws IOException {
private FieldInfo[] readFields( DataInputStream input ) throws IOException {
FieldInfo[] fields = new FieldInfo[input.readUnsignedShort()];
for( int i = 0; i < fields.length; i++ ) {
fields[i] = new FieldInfo( input, constantPool );
@ -224,7 +261,7 @@ public class ClassFile {
return fields;
}
private MethodInfo[] readMethods() throws IOException {
private MethodInfo[] readMethods( DataInputStream input ) throws IOException {
MethodInfo[] methods = new MethodInfo[input.readUnsignedShort()];
for( int i = 0; i < methods.length; i++ ) {
methods[i] = new MethodInfo( input, constantPool, this );

View File

@ -1,5 +1,5 @@
/*
Copyright 2011 - 2019 Volker Berlin (i-net software)
Copyright 2011 - 2020 Volker Berlin (i-net software)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -147,4 +147,25 @@ public class ConstantPool {
public Object get( int index ) {
return constantPool[index];
}
/**
* Set a value in the constant pool.
*
* @param index
* the index
* @param value
* the new value
*/
void set( int index, Object value ) {
constantPool[index] = value;
}
/**
* Get the count of entries in the pool.
*
* @return the count
*/
int size() {
return constantPool.length;
}
}

View File

@ -18,6 +18,7 @@ package de.inetsoftware.jwebassembly.module;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import javax.annotation.Nullable;
@ -31,7 +32,9 @@ import de.inetsoftware.classparser.WeakValueCache;
*/
public class ClassFileLoader {
private final WeakValueCache<String, ClassFile> CACHE = new WeakValueCache<>();
private final HashMap<String, ClassFile> replace = new HashMap<>();
private final WeakValueCache<String, ClassFile> weakCache = new WeakValueCache<>();
private final ClassLoader loader;
@ -56,16 +59,32 @@ public class ClassFileLoader {
*/
@Nullable
public ClassFile get( String className ) throws IOException {
ClassFile classFile = CACHE.get( className );
ClassFile classFile = replace.get( className );
if( classFile != null ) {
return classFile;
}
classFile = weakCache.get( className );
if( classFile != null ) {
return classFile;
}
InputStream stream = loader.getResourceAsStream( className + ".class" );
if( stream != null ) {
classFile = new ClassFile( stream );
CACHE.put( className, classFile );
weakCache.put( className, classFile );
}
return classFile;
}
/**
* Replace the class in the cache with the given instance.
*
* @param className
* the name of the class to replace
* @param classFile
* the replasing ClassFile
*/
public void replace( String className, ClassFile classFile ) {
classFile = new ClassFile( className, classFile );
replace.put( className, classFile );
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2017 - 2019 Volker Berlin (i-net software)
* Copyright 2017 - 2020 Volker Berlin (i-net software)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -158,8 +158,19 @@ public class ModuleGenerator {
* the class file
* @throws WasmException
* if some Java code can't converted
* @throws IOException
* if any I/O error occur
*/
public void prepare( ClassFile classFile ) {
public void prepare( ClassFile classFile ) throws IOException {
// check if this class replace another class
Map<String,Object> annotationValues;
if( (annotationValues = classFile.getAnnotation( JWebAssembly.REPLACE_ANNOTATION )) != null ) {
String signatureName = (String)annotationValues.get( "value" );
if( signatureName != null ) {
classFileLoader.replace( signatureName, classFile );
}
}
iterateMethods( classFile, m -> prepareMethod( m ) );
}