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 { public class ClassFile {
private final DataInputStream input;
private final int minorVersion; private final int minorVersion;
private final int majorVersion; private final int majorVersion;
@ -71,7 +69,7 @@ public class ClassFile {
* if this input stream reaches the end before reading the class file. * if this input stream reaches the end before reading the class file.
*/ */
public ClassFile( InputStream stream ) throws IOException { public ClassFile( InputStream stream ) throws IOException {
this.input = new DataInputStream( stream ); DataInputStream input = new DataInputStream( stream );
int magic = input.readInt(); int magic = input.readInt();
if( magic != 0xCAFEBABE ) { if( magic != 0xCAFEBABE ) {
throw new IOException( "Invalid class magic: " + Integer.toHexString( magic ) ); throw new IOException( "Invalid class magic: " + Integer.toHexString( magic ) );
@ -87,8 +85,8 @@ public class ClassFile {
for( int i = 0; i < interfaces.length; i++ ) { for( int i = 0; i < interfaces.length; i++ ) {
interfaces[i] = (ConstantClass)constantPool.get( input.readUnsignedShort() ); interfaces[i] = (ConstantClass)constantPool.get( input.readUnsignedShort() );
} }
fields = readFields(); fields = readFields( input );
methods = readMethods(); methods = readMethods( input );
attributes = new Attributes( input, constantPool ); attributes = new Attributes( input, constantPool );
stream.close(); 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. * Get value of SourceFile if available.
* *
@ -216,7 +253,7 @@ public class ClassFile {
return accessFlags; return accessFlags;
} }
private FieldInfo[] readFields() throws IOException { private FieldInfo[] readFields( DataInputStream input ) throws IOException {
FieldInfo[] fields = new FieldInfo[input.readUnsignedShort()]; FieldInfo[] fields = new FieldInfo[input.readUnsignedShort()];
for( int i = 0; i < fields.length; i++ ) { for( int i = 0; i < fields.length; i++ ) {
fields[i] = new FieldInfo( input, constantPool ); fields[i] = new FieldInfo( input, constantPool );
@ -224,7 +261,7 @@ public class ClassFile {
return fields; return fields;
} }
private MethodInfo[] readMethods() throws IOException { private MethodInfo[] readMethods( DataInputStream input ) throws IOException {
MethodInfo[] methods = new MethodInfo[input.readUnsignedShort()]; MethodInfo[] methods = new MethodInfo[input.readUnsignedShort()];
for( int i = 0; i < methods.length; i++ ) { for( int i = 0; i < methods.length; i++ ) {
methods[i] = new MethodInfo( input, constantPool, this ); 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"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with 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 ) { public Object get( int index ) {
return constantPool[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.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.HashMap;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -31,7 +32,9 @@ import de.inetsoftware.classparser.WeakValueCache;
*/ */
public class ClassFileLoader { 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; private final ClassLoader loader;
@ -56,16 +59,32 @@ public class ClassFileLoader {
*/ */
@Nullable @Nullable
public ClassFile get( String className ) throws IOException { 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 ) { if( classFile != null ) {
return classFile; return classFile;
} }
InputStream stream = loader.getResourceAsStream( className + ".class" ); InputStream stream = loader.getResourceAsStream( className + ".class" );
if( stream != null ) { if( stream != null ) {
classFile = new ClassFile( stream ); classFile = new ClassFile( stream );
CACHE.put( className, classFile ); weakCache.put( className, classFile );
} }
return 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -158,8 +158,19 @@ public class ModuleGenerator {
* the class file * the class file
* @throws WasmException * @throws WasmException
* if some Java code can't converted * 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 ) ); iterateMethods( classFile, m -> prepareMethod( m ) );
} }