diff --git a/src/de/inetsoftware/classparser/ClassFile.java b/src/de/inetsoftware/classparser/ClassFile.java index a4ced98..aa4db6a 100644 --- a/src/de/inetsoftware/classparser/ClassFile.java +++ b/src/de/inetsoftware/classparser/ClassFile.java @@ -19,6 +19,8 @@ package de.inetsoftware.classparser; import java.io.DataInputStream; import java.io.IOException; import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Map; @@ -48,9 +50,9 @@ public class ClassFile { private final ConstantClass[] interfaces; - private final FieldInfo[] fields; + private FieldInfo[] fields; - private final MethodInfo[] methods; + private MethodInfo[] methods; private final Attributes attributes; @@ -136,16 +138,27 @@ public class ClassFile { methods = classFile.methods; attributes = classFile.attributes; + patchConstantPool( classFile.thisClass.getName(), thisClass ); + } + + /** + * Replace the reference to the Class in the the constant pool. + * + * @param origClassName + * the class name that should be replaced. + * @param thisClass + * the reference of the class that should be used. + */ + private void patchConstantPool( String origClassName, ConstantClass thisClass ) { // 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; + } else if( obj instanceof ConstantRef ) { + ConstantRef ref = (ConstantRef)obj; if( ref.getClassName().equals( origClassName ) ) { ConstantNameAndType nameAndType = new ConstantNameAndType( ref.getName(), ref.getType() ); constantPool.set( i, new ConstantFieldRef( thisClass, nameAndType ) ); @@ -301,4 +314,31 @@ public class ClassFile { public static enum Type { Class, Interface, Enum; } + + /** + * Extends this class with the methods and fields of the partial class. + * + * @param partialClassFile + * extension of the class + */ + public void partial( ClassFile partialClassFile ) { + ArrayList allMethods = new ArrayList<>( Arrays.asList( methods ) ); + for( MethodInfo m : partialClassFile.methods ) { + if( getMethod( m.getName(), m.getType() ) == null ) { + m.setDeclaringClassFile( this ); + allMethods.add( m ); + } + } + methods = allMethods.toArray( methods ); + + ArrayList allFields = new ArrayList<>( Arrays.asList( fields ) ); + for( FieldInfo field : partialClassFile.fields ) { + if( getField( field.getName() ) == null ) { + allFields.add( field ); + } + } + fields = allFields.toArray( fields ); + + partialClassFile.patchConstantPool( partialClassFile.thisClass.getName(), thisClass ); + } } diff --git a/src/de/inetsoftware/classparser/MethodInfo.java b/src/de/inetsoftware/classparser/MethodInfo.java index 66d314a..27de2b5 100644 --- a/src/de/inetsoftware/classparser/MethodInfo.java +++ b/src/de/inetsoftware/classparser/MethodInfo.java @@ -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. @@ -21,6 +21,7 @@ import java.io.IOException; import java.util.Collections; import java.util.Map; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import de.inetsoftware.classparser.Attributes.AttributeInfo; @@ -200,4 +201,14 @@ public class MethodInfo implements Member { public ConstantPool getConstantPool() { return constantPool; } + + /** + * Replace the reference to the ClassFile + * + * @param classFile + * the new value + */ + void setDeclaringClassFile( @Nonnull ClassFile classFile ) { + this.classFile = classFile; + } } diff --git a/src/de/inetsoftware/jwebassembly/JWebAssembly.java b/src/de/inetsoftware/jwebassembly/JWebAssembly.java index 86723cd..ed969dd 100644 --- a/src/de/inetsoftware/jwebassembly/JWebAssembly.java +++ b/src/de/inetsoftware/jwebassembly/JWebAssembly.java @@ -88,6 +88,11 @@ public class JWebAssembly { */ public static final String REPLACE_ANNOTATION = "de.inetsoftware.jwebassembly.api.annotation.Replace"; + /** + * The name of the annotation for partial class another class of the Java runtime. + */ + public static final String PARTIAL_ANNOTATION = "de.inetsoftware.jwebassembly.api.annotation.Partial"; + /** * If the GC feature of WASM should be use or the GC of the JavaScript host. If true use the GC instructions of WASM. */ diff --git a/src/de/inetsoftware/jwebassembly/module/ClassFileLoader.java b/src/de/inetsoftware/jwebassembly/module/ClassFileLoader.java index 4945c7c..95b74e2 100644 --- a/src/de/inetsoftware/jwebassembly/module/ClassFileLoader.java +++ b/src/de/inetsoftware/jwebassembly/module/ClassFileLoader.java @@ -104,15 +104,31 @@ public class ClassFileLoader { } /** - * Replace the class in the cache with the given instance. + * Replace the class in the cache with the given instance to the loader cache. * * @param className * the name of the class to replace * @param classFile - * the replasing ClassFile + * the replacing ClassFile */ - public void replace( String className, ClassFile classFile ) { + void replace( String className, ClassFile classFile ) { classFile = new ClassFile( className, classFile ); replace.put( className, classFile ); } + + /** + * Add a partial class with the given instance to the loader cache. + * + * @param className + * the name of the class to replace + * @param partialClassFile + * the partial ClassFile + * @throws IOException + * If any I/O error occur + */ + void partial( String className, ClassFile partialClassFile ) throws IOException { + ClassFile classFile = get( className ); + replace.put( className, classFile ); + classFile.partial( partialClassFile ); + } } diff --git a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java index bba9122..3f43540 100644 --- a/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java +++ b/src/de/inetsoftware/jwebassembly/module/ModuleGenerator.java @@ -172,6 +172,14 @@ public class ModuleGenerator { } } + // check if this class extends another class with partial code + if( (annotationValues = classFile.getAnnotation( JWebAssembly.PARTIAL_ANNOTATION )) != null ) { + String signatureName = (String)annotationValues.get( "value" ); + if( signatureName != null ) { + classFileLoader.partial( signatureName, classFile ); + } + } + iterateMethods( classFile, m -> prepareMethod( m ) ); }