blob: 86dc2cae82a22576f03db543d297d0e8e7405977 [file] [log] [blame]
package org.apache.directmemory.lightning.internal.generator;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.directmemory.lightning.Marshaller;
import org.apache.directmemory.lightning.MarshallerStrategy;
import org.apache.directmemory.lightning.SerializationStrategy;
import org.apache.directmemory.lightning.exceptions.SerializerMarshallerGeneratorException;
import org.apache.directmemory.lightning.instantiator.ObjectInstantiatorFactory;
import org.apache.directmemory.lightning.internal.ClassDescriptorAwareSerializer;
import org.apache.directmemory.lightning.internal.InternalMarshallerStrategy;
import org.apache.directmemory.lightning.internal.util.ClassUtil;
import org.apache.directmemory.lightning.logging.Logger;
import org.apache.directmemory.lightning.metadata.PropertyDescriptor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
public class BytecodeMarshallerGenerator
implements Opcodes, GeneratorConstants, MarshallerGenerator
{
private final GeneratorClassLoader classloader = CreateClassLoader.createClassLoader( getClass().getClassLoader() );
@Override
public Marshaller generateMarshaller( Class<?> type, List<PropertyDescriptor> propertyDescriptors,
Map<Class<?>, Marshaller> marshallers,
ClassDescriptorAwareSerializer serializer,
SerializationStrategy serializationStrategy,
ObjectInstantiatorFactory objectInstantiatorFactory,
File debugCacheDirectory, Logger logger )
{
try
{
ClassWriter cw = new ClassWriter( 0 );
// Copy properties and sort them by name
List<PropertyDescriptor> propertyDescriptorsCopy = new ArrayList<PropertyDescriptor>( propertyDescriptors );
Collections.sort( propertyDescriptorsCopy );
// Build className e.g. "SomeTypeMarshaller$$X$$Lightning"
String className =
new StringBuilder( !type.isArray() ? type.getSimpleName() : type.getComponentType().getSimpleName()
+ "Array" ).append( "Marshaller" ).append( GENEREATED_CLASS_ID.getAndIncrement() ).append( "Lightning" ).toString();
// Build class
cw.visit( V1_6, ACC_PUBLIC & ACC_SUPER, className, null, SUPER_CLASS_INTERNAL_TYPE, null );
// Build marshaller fields
createMarshallerFields( cw, propertyDescriptorsCopy );
// Build constructor
createConstructor( cw, className, propertyDescriptorsCopy );
// Build Marshaller#marshall method
createMarshallMethod( cw, className, type, serializationStrategy, propertyDescriptorsCopy );
// Build Marshaller#unmarshall method
createUnmarshallMethod( cw, className, type, propertyDescriptorsCopy );
// Closing class visit
cw.visitEnd();
final byte[] bytecode = cw.toByteArray();
if ( debugCacheDirectory != null )
{
File file = new File( debugCacheDirectory, className + ".class" );
FileOutputStream out = new FileOutputStream( file );
try
{
out.write( bytecode );
out.flush();
}
finally
{
try
{
out.close();
}
catch ( IOException e )
{
logger.warn( String.format( "Class %s could not be cached", className ), e );
}
}
}
Class<? extends Marshaller> generatedClass = classloader.loadClass( bytecode );
Constructor<? extends Marshaller> constructor =
generatedClass.getConstructor( Class.class, Map.class, ClassDescriptorAwareSerializer.class,
ObjectInstantiatorFactory.class, List.class, MarshallerStrategy.class );
constructor.setAccessible( true );
return constructor.newInstance( type, marshallers, serializer, objectInstantiatorFactory,
propertyDescriptorsCopy, new InternalMarshallerStrategy() );
}
catch ( Exception e )
{
throw new SerializerMarshallerGeneratorException(
"Marshaller for type " + type + " could not be generated",
e );
}
}
private void createMarshallerFields( ClassWriter cw, List<PropertyDescriptor> propertyDescriptors )
{
for ( int i = 0; i < propertyDescriptors.size(); i++ )
{
PropertyDescriptor propertyDescriptor = propertyDescriptors.get( i );
FieldVisitor fv = null;
// Write PropertyDescriptor field
fv =
cw.visitField( ACC_FINAL & ACC_PRIVATE, toFinalFieldName( "descriptor", propertyDescriptor ),
PROPERTYDESCRIPTOR_CLASS_DESCRIPTOR, null, null );
fv.visitEnd();
if ( propertyDescriptor.getType().isArray()
&& !propertyDescriptor.getType().getComponentType().isPrimitive() )
{
// Write ComponentType PropertyDescriptor field
fv =
cw.visitField( ACC_FINAL & ACC_PRIVATE, toFinalFieldName( "component", propertyDescriptor ),
CHEATINGPROPERTYDESCRIPTOR_CLASS_DESCRIPTOR, null, null );
fv.visitEnd();
}
// Write Marshaller field
fv =
cw.visitField( ACC_FINAL & ACC_PRIVATE, toFinalFieldName( "marshaller", propertyDescriptor ),
MARSHALLER_CLASS_DESCRIPTOR, null, null );
fv.visitEnd();
// Write PropertyAccessor field
fv =
cw.visitField( ACC_FINAL & ACC_PRIVATE, toFinalFieldName( "accessor", propertyDescriptor ),
PROPERTYACCESSOR_CLASS_DESCRIPTOR, null, null );
fv.visitEnd();
}
}
private void createConstructor( ClassWriter cw, String className, List<PropertyDescriptor> propertyDescriptors )
{
MethodVisitor mv = cw.visitMethod( ACC_PUBLIC, "<init>", MARSHALLER_CONSTRUCTOR_SIGNATURE, null, null );
mv.visitCode();
// Load this
mv.visitVarInsn( ALOAD, 0 );
// Load first parameter type (Class)
mv.visitVarInsn( ALOAD, 1 );
// Load second parameter type (Map)
mv.visitVarInsn( ALOAD, 2 );
// Load third parameter type (ClassDescriptorAwaySerializer)
mv.visitVarInsn( ALOAD, 3 );
// Load fourth parameter type (ObjenesisSerializer)
mv.visitVarInsn( ALOAD, 4 );
// Call super(Class, Map)
mv.visitMethodInsn( INVOKESPECIAL, SUPER_CLASS_INTERNAL_TYPE, "<init>", MARSHALLER_SUPER_CONSTRUCTOR_SIGNATURE );
// Fill fields with marshallers
for ( int i = 0; i < propertyDescriptors.size(); i++ )
{
PropertyDescriptor propertyDescriptor = propertyDescriptors.get( i );
String fieldName = toFinalFieldName( "marshaller", propertyDescriptor );
mv.visitVarInsn( ALOAD, 0 );
mv.visitVarInsn( ALOAD, 0 );
// Load property type
mv.visitVarInsn( ALOAD, 5 );
mv.visitIntInsn( BIPUSH, i );
mv.visitMethodInsn( INVOKEINTERFACE, LIST_CLASS_INTERNAL_TYPE, "get", "(I)Ljava/lang/Object;" );
// Store PropertyDescriptor
mv.visitTypeInsn( CHECKCAST, PROPERTYDESCRIPTOR_CLASS_INTERNAL_TYPE );
mv.visitFieldInsn( PUTFIELD, className, toFinalFieldName( "descriptor", propertyDescriptor ),
PROPERTYDESCRIPTOR_CLASS_DESCRIPTOR );
if ( propertyDescriptor.getType().isArray()
&& !propertyDescriptor.getType().getComponentType().isPrimitive() )
{
Label labelNonNull = new Label();
// Get type from PropertyAccessor
mv.visitVarInsn( ALOAD, 0 );
mv.visitFieldInsn( GETFIELD, className, toFinalFieldName( "descriptor", propertyDescriptor ),
PROPERTYDESCRIPTOR_CLASS_DESCRIPTOR );
mv.visitMethodInsn( INVOKEINTERFACE, PROPERTYDESCRIPTOR_CLASS_INTERNAL_TYPE, "getType",
"()Ljava/lang/Class;" );
// Get array component type
mv.visitMethodInsn( INVOKEVIRTUAL, CLASS_CLASS_INTERNAL_TYPE, "getComponentType",
CLASS_GET_COMPONENT_TYPE );
mv.visitVarInsn( ASTORE, 9 );
// Generate cheating PropertyDescriptor for component type
mv.visitVarInsn( ALOAD, 0 );
mv.visitTypeInsn( NEW, CHEATINGPROPERTYDESCRIPTOR_CLASS_INTERNAL_TYPE );
mv.visitInsn( DUP );
mv.visitLdcInsn( propertyDescriptor.getPropertyName() + "Element" );
mv.visitVarInsn( ALOAD, 9 );
mv.visitInsn( ACONST_NULL );
mv.visitMethodInsn( INVOKESPECIAL, CHEATINGPROPERTYDESCRIPTOR_CLASS_INTERNAL_TYPE, "<init>",
CHEATINGPROPERTYDESCRIPTOR_CONSTRUCTOR );
mv.visitFieldInsn( PUTFIELD, className, toFinalFieldName( "component", propertyDescriptor ),
CHEATINGPROPERTYDESCRIPTOR_CLASS_DESCRIPTOR );
// Search marshaller by using interal ones
mv.visitVarInsn( ALOAD, 6 );
mv.visitVarInsn( ALOAD, 9 );
mv.visitInsn( ACONST_NULL );
mv.visitMethodInsn( INVOKEINTERFACE, MARSHALLERSTRATEGY_CLASS_INTERNAL_TYPE, "getMarshaller",
MARSHALLERSTRATEGY_GET_MARSHALLER_SIGNATURE );
mv.visitVarInsn( ASTORE, 8 );
mv.visitVarInsn( ALOAD, 8 );
// Search marshaller for property type
mv.visitJumpInsn( IFNONNULL, labelNonNull );
mv.visitVarInsn( ALOAD, 0 );
mv.visitVarInsn( ALOAD, 0 );
mv.visitFieldInsn( GETFIELD, className, toFinalFieldName( "component", propertyDescriptor ),
CHEATINGPROPERTYDESCRIPTOR_CLASS_DESCRIPTOR );
mv.visitMethodInsn( INVOKEVIRTUAL, SUPER_CLASS_INTERNAL_TYPE, "findMarshaller",
MARSHALLER_FIND_MARSHALLER_SIGNATURE );
mv.visitVarInsn( ASTORE, 8 );
// Save marshaller to field
mv.visitLabel( labelNonNull );
mv.visitVarInsn( ALOAD, 0 );
mv.visitVarInsn( ALOAD, 8 );
mv.visitFieldInsn( PUTFIELD, className, toFinalFieldName( "marshaller", propertyDescriptor ),
MARSHALLER_CLASS_DESCRIPTOR );
}
else
{
// Check if marshaller is defined
mv.visitVarInsn( ALOAD, 0 );
mv.visitVarInsn( ALOAD, 0 );
mv.visitVarInsn( ALOAD, 0 );
mv.visitFieldInsn( GETFIELD, className, toFinalFieldName( "descriptor", propertyDescriptor ),
PROPERTYDESCRIPTOR_CLASS_DESCRIPTOR );
mv.visitMethodInsn( INVOKEVIRTUAL, SUPER_CLASS_INTERNAL_TYPE, "findMarshaller",
MARSHALLER_FIND_MARSHALLER_SIGNATURE );
mv.visitFieldInsn( PUTFIELD, className, fieldName, MARSHALLER_CLASS_DESCRIPTOR );
}
// Load this to method stack
mv.visitVarInsn( ALOAD, 0 );
mv.visitInsn( DUP );
// Load property accessor
mv.visitFieldInsn( GETFIELD, className, toFinalFieldName( "descriptor", propertyDescriptor ),
PROPERTYDESCRIPTOR_CLASS_DESCRIPTOR );
mv.visitMethodInsn( INVOKEINTERFACE, PROPERTYDESCRIPTOR_CLASS_INTERNAL_TYPE, "getPropertyAccessor",
PROPERTY_DESCRIPTOR_GET_PROPERTYACCESSOR_SIGNATURE );
// Save PropertyAccessor to field
mv.visitFieldInsn( PUTFIELD, className, toFinalFieldName( "accessor", propertyDescriptor ),
PROPERTYACCESSOR_CLASS_DESCRIPTOR );
}
mv.visitInsn( RETURN );
mv.visitMaxs( -1, 12 );
mv.visitEnd();
}
private void createMarshallMethod( ClassWriter cw, String className, Class<?> type,
SerializationStrategy serializationStrategy,
List<PropertyDescriptor> propertyDescriptors )
{
MethodVisitor mv =
cw.visitMethod( ACC_PUBLIC, "marshall", MARSHALLER_MARSHALL_SIGNATURE, null, MARSHALLER_EXCEPTIONS );
// If element type is not reference capable or SerializationStrategy is
// not SizeOptimized just prevent generation of code
if ( serializationStrategy == SerializationStrategy.SizeOptimized && ClassUtil.isReferenceCapable( type ) )
{
// Load this to method stack
mv.visitVarInsn( ALOAD, 0 );
// Load value to method stack
mv.visitVarInsn( ALOAD, 1 );
// Load type to method stack
mv.visitVarInsn( ALOAD, 2 );
// Load dataOutput to method stack
mv.visitVarInsn( ALOAD, 3 );
// Load serializationContext to method stack
mv.visitVarInsn( ALOAD, 4 );
// Call super.isAlreadyMarshalled(...);
mv.visitMethodInsn( INVOKEVIRTUAL, SUPER_CLASS_INTERNAL_TYPE, "isAlreadyMarshalled",
MARSHALLER_IS_ALREADY_MARSHALLED_SIGNATURE );
// Label if value is not yet marshalled
Label notYetMarshalled = new Label();
// Test if already marshalled
mv.visitJumpInsn( IFEQ, notYetMarshalled );
// If marshalled - just return
mv.visitInsn( RETURN );
// Visit label - if not yet marshalled - marshall it
mv.visitLabel( notYetMarshalled );
}
for ( PropertyDescriptor propertyDescriptor : propertyDescriptors )
{
if ( propertyDescriptor.getType().isArray()
&& !propertyDescriptor.getType().getComponentType().isPrimitive() )
{
visitObjectArrayPropertyAccessorRead( mv, className, propertyDescriptor );
}
else
{
visitValuePropertyAccessorRead( mv, className, propertyDescriptor );
}
}
// Add Return instruction
mv.visitInsn( RETURN );
// End visiting
mv.visitMaxs( 9, 9 );
mv.visitEnd();
}
private void visitValuePropertyAccessorRead( MethodVisitor mv, String className,
PropertyDescriptor propertyDescriptor )
{
Class<?> propertyType = propertyDescriptor.getType();
// Load this to method stack
mv.visitVarInsn( ALOAD, 0 );
// Load property marshaller on stack
mv.visitFieldInsn( GETFIELD, className, toFinalFieldName( "marshaller", propertyDescriptor ),
MARSHALLER_CLASS_DESCRIPTOR );
// Load this to method stack
mv.visitVarInsn( ALOAD, 0 );
// Read PropertyAccessor from field
mv.visitFieldInsn( GETFIELD, className, toFinalFieldName( "accessor", propertyDescriptor ),
PROPERTYACCESSOR_CLASS_DESCRIPTOR );
// Load value to method stack
mv.visitVarInsn( ALOAD, 1 );
// Load value by type on stack
visitPropertyAccessorValueRead( propertyType, mv );
// If type is primitive add some "autoboxing" magic
if ( propertyType.isPrimitive() )
{
visitWrapperAutoboxing( propertyType, mv );
}
// Load type to method stack
mv.visitVarInsn( ALOAD, 0 );
mv.visitFieldInsn( GETFIELD, className, toFinalFieldName( "descriptor", propertyDescriptor ),
PROPERTYDESCRIPTOR_CLASS_DESCRIPTOR );
// Load DataOutput to method stack
mv.visitVarInsn( ALOAD, 3 );
// Load SerializationContext to method stack
mv.visitVarInsn( ALOAD, 4 );
// Call Marshaller#marshall on properties marshaller
mv.visitMethodInsn( INVOKEINTERFACE, MARSHALLER_CLASS_INTERNAL_TYPE, "marshall", MARSHALLER_MARSHALL_SIGNATURE );
}
private void visitObjectArrayPropertyAccessorRead( MethodVisitor mv, String className,
PropertyDescriptor propertyDescriptor )
{
Class<?> propertyType = propertyDescriptor.getType();
// Load this to method stack
mv.visitVarInsn( ALOAD, 0 );
// Read PropertyAccessor from field
mv.visitFieldInsn( GETFIELD, className, toFinalFieldName( "accessor", propertyDescriptor ),
PROPERTYACCESSOR_CLASS_DESCRIPTOR );
mv.visitTypeInsn( CHECKCAST, ARRAYPROPERTYACCESSOR_CLASS_INTERNAL_TYPE );
mv.visitVarInsn( ASTORE, 8 );
// Load property type
mv.visitVarInsn( ALOAD, 8 );
mv.visitInsn( DUP );
mv.visitMethodInsn( INVOKEINTERFACE, PROPERTYACCESSOR_CLASS_INTERNAL_TYPE, "getType",
OBJECT_GET_CLASS_SIGNATURE );
mv.visitVarInsn( ASTORE, 5 );
// Load value to method stack
mv.visitVarInsn( ALOAD, 1 );
// Save array to stack position 6
visitPropertyAccessorValueRead( propertyType, mv );
mv.visitTypeInsn( CHECKCAST, Type.getType( propertyType ).getInternalName() );
mv.visitVarInsn( ASTORE, 6 );
// Save length to stream
mv.visitVarInsn( ALOAD, 3 );
mv.visitVarInsn( ALOAD, 6 );
mv.visitInsn( ARRAYLENGTH );
mv.visitMethodInsn( INVOKEINTERFACE, DATAOUTPUT_CLASS_INTERNAL_TYPE, "writeInt", "(I)V" );
// Loop over every element in array
Label forLoopEnd = new Label();
Label forLoopStart = new Label();
mv.visitInsn( ICONST_0 );
mv.visitVarInsn( ISTORE, 7 );
mv.visitJumpInsn( GOTO, forLoopEnd );
mv.visitLabel( forLoopStart );
// Load this to method stack
mv.visitVarInsn( ALOAD, 0 );
// Load property marshaller on stack
mv.visitFieldInsn( GETFIELD, className, toFinalFieldName( "marshaller", propertyDescriptor ),
MARSHALLER_CLASS_DESCRIPTOR );
// Load PropertyAccessor to method stack
mv.visitVarInsn( ALOAD, 8 );
// Load array to method stack
mv.visitVarInsn( ALOAD, 6 );
// Load index to method stack
mv.visitVarInsn( ILOAD, 7 );
// Get value from array
mv.visitMethodInsn( INVOKEINTERFACE, ARRAYPROPERTYACCESSOR_CLASS_INTERNAL_TYPE, "readObject",
PROPERTY_ACCESSOR_ARRAY_READ_OBJECT_SIGNATURE );
mv.visitTypeInsn( CHECKCAST, Type.getType( propertyType.getComponentType() ).getInternalName() );
// If type is primitive add some "autoboxing" magic
if ( propertyType.getComponentType().isPrimitive() )
{
visitWrapperAutoboxing( propertyType.getComponentType(), mv );
}
// Load type to method stack
mv.visitVarInsn( ALOAD, 0 );
mv.visitFieldInsn( GETFIELD, className, toFinalFieldName( "component", propertyDescriptor ),
CHEATINGPROPERTYDESCRIPTOR_CLASS_DESCRIPTOR );
// Load DataOutput to method stack
mv.visitVarInsn( ALOAD, 3 );
// Load SerializationContext to method stack
mv.visitVarInsn( ALOAD, 4 );
// Call Marshaller#marshall on properties marshaller
mv.visitMethodInsn( INVOKEINTERFACE, MARSHALLER_CLASS_INTERNAL_TYPE, "marshall", MARSHALLER_MARSHALL_SIGNATURE );
// Test if loop ends
mv.visitIincInsn( 7, 1 );
mv.visitLabel( forLoopEnd );
mv.visitVarInsn( ILOAD, 7 );
mv.visitVarInsn( ALOAD, 6 );
mv.visitInsn( ARRAYLENGTH );
mv.visitJumpInsn( IF_ICMPLT, forLoopStart );
}
private void createUnmarshallMethod( ClassWriter cw, String className, Class<?> type,
List<PropertyDescriptor> propertyDescriptors )
{
MethodVisitor mv =
cw.visitMethod( ACC_PUBLIC, "unmarshall", MARSHALLER_UNMARSHALL_SIGNATURE, null, MARSHALLER_EXCEPTIONS );
for ( PropertyDescriptor propertyDescriptor : propertyDescriptors )
{
if ( propertyDescriptor.getType().isArray()
&& !propertyDescriptor.getType().getComponentType().isPrimitive() )
{
visitObjectArrayPropertyAccessorWrite( mv, className, propertyDescriptor );
}
else
{
visitValuePropertyAccessorWrite( mv, className, propertyDescriptor );
}
}
// Load instance to method stack
mv.visitVarInsn( ALOAD, 1 );
// Add Return statement
visitReturn( type, mv );
// End visiting
mv.visitMaxs( 11, 11 );
mv.visitEnd();
}
private void visitValuePropertyAccessorWrite( MethodVisitor mv, String className,
PropertyDescriptor propertyDescriptor )
{
Class<?> propertyType = propertyDescriptor.getType();
// Load this to method stack
mv.visitVarInsn( ALOAD, 0 );
// Read PropertyAccessor from field
mv.visitFieldInsn( GETFIELD, className, toFinalFieldName( "accessor", propertyDescriptor ),
PROPERTYACCESSOR_CLASS_DESCRIPTOR );
// Store PropertyAccessor for later use
mv.visitVarInsn( ASTORE, 5 );
// Load this to method stack
mv.visitVarInsn( ALOAD, 0 );
// Load property marshaller to method stack
mv.visitFieldInsn( GETFIELD, className, toFinalFieldName( "marshaller", propertyDescriptor ),
MARSHALLER_CLASS_DESCRIPTOR );
// Load this to method stack
mv.visitVarInsn( ALOAD, 0 );
// Load PropertyDescriptor to method stack
mv.visitFieldInsn( GETFIELD, className, toFinalFieldName( "descriptor", propertyDescriptor ),
PROPERTYDESCRIPTOR_CLASS_DESCRIPTOR );
// Load DataInput to method stack
mv.visitVarInsn( ALOAD, 3 );
// Load SerializationContext to method stack
mv.visitVarInsn( ALOAD, 4 );
// Call Marshaller#unmarshall on properties marshaller
mv.visitMethodInsn( INVOKEINTERFACE, MARSHALLER_CLASS_INTERNAL_TYPE, "unmarshall",
MARSHALLER_BASE_UNMARSHALL_SIGNATURE );
// Save value
mv.visitVarInsn( ASTORE, 6 );
// Load PropertyAccessor to method stack
mv.visitVarInsn( ALOAD, 5 );
// Load instance to method stack
mv.visitVarInsn( ALOAD, 1 );
// Load value to method stack
mv.visitVarInsn( ALOAD, 6 );
// If type is primitive add some "autoboxing" magic
if ( propertyType.isPrimitive() )
{
visitPrimitiveAutoboxing( propertyType, mv );
}
// Call PropertyAccessor#writeX
visitPropertyAccessorValueWrite( propertyType, mv );
}
private void visitObjectArrayPropertyAccessorWrite( MethodVisitor mv, String className,
PropertyDescriptor propertyDescriptor )
{
Class<?> propertyType = propertyDescriptor.getType();
Class<?> componentType = propertyType.getComponentType();
// Read size
mv.visitVarInsn( ALOAD, 3 );
mv.visitMethodInsn( INVOKEINTERFACE, DATAINPUT_CLASS_INTERNAL_TYPE, "readInt", "()I" );
mv.visitInsn( DUP );
mv.visitVarInsn( ISTORE, 5 );
// Instantiate array
mv.visitTypeInsn( ANEWARRAY, Type.getType( componentType ).getInternalName() );
mv.visitVarInsn( ASTORE, 6 );
// Read PropertyAccessor from field
mv.visitVarInsn( ALOAD, 0 );
mv.visitFieldInsn( GETFIELD, className, toFinalFieldName( "accessor", propertyDescriptor ),
PROPERTYACCESSOR_CLASS_DESCRIPTOR );
mv.visitVarInsn( ASTORE, 9 );
// Get component type
mv.visitVarInsn( ALOAD, 0 );
mv.visitFieldInsn( GETFIELD, className, toFinalFieldName( "component", propertyDescriptor ),
CHEATINGPROPERTYDESCRIPTOR_CLASS_DESCRIPTOR );
mv.visitVarInsn( ASTORE, 8 );
mv.visitVarInsn( ALOAD, 0 );
mv.visitFieldInsn( GETFIELD, className, toFinalFieldName( "marshaller", propertyDescriptor ),
MARSHALLER_CLASS_DESCRIPTOR );
mv.visitVarInsn( ASTORE, 10 );
// For loop
Label forLoopStart = new Label();
Label forLoopEnd = new Label();
mv.visitInsn( ICONST_0 );
mv.visitVarInsn( ISTORE, 7 );
mv.visitJumpInsn( GOTO, forLoopEnd );
mv.visitLabel( forLoopStart );
// Write value to array
mv.visitVarInsn( ALOAD, 9 );
mv.visitVarInsn( ALOAD, 6 );
mv.visitVarInsn( ILOAD, 7 );
// Read value from stream to 4th stack position
mv.visitVarInsn( ALOAD, 10 );
mv.visitVarInsn( ALOAD, 8 );
mv.visitVarInsn( ALOAD, 3 );
mv.visitVarInsn( ALOAD, 4 );
mv.visitMethodInsn( INVOKEINTERFACE, MARSHALLER_CLASS_INTERNAL_TYPE, "unmarshall",
MARSHALLER_BASE_UNMARSHALL_SIGNATURE );
mv.visitMethodInsn( INVOKEINTERFACE, ARRAYPROPERTYACCESSOR_CLASS_INTERNAL_TYPE, "writeObject",
PROPERTY_ACCESSOR_ARRAY_WRITE_OBJECT_SIGNATURE );
// Increment counter
mv.visitIincInsn( 7, 1 );
// Test for loop end
mv.visitLabel( forLoopEnd );
mv.visitVarInsn( ILOAD, 7 );
mv.visitVarInsn( ILOAD, 5 );
mv.visitJumpInsn( IF_ICMPLT, forLoopStart );
// Write array to object
mv.visitVarInsn( ALOAD, 9 );
mv.visitVarInsn( ALOAD, 1 );
mv.visitVarInsn( ALOAD, 6 );
visitPropertyAccessorValueWrite( propertyType.getComponentType(), mv );
}
private void visitReturn( Class<?> type, MethodVisitor mv )
{
int returnOpcode = ARETURN;
if ( type == boolean.class )
{
returnOpcode = IRETURN;
}
else if ( type == byte.class )
{
returnOpcode = IRETURN;
}
else if ( type == char.class )
{
returnOpcode = IRETURN;
}
else if ( type == short.class )
{
returnOpcode = IRETURN;
}
else if ( type == int.class )
{
returnOpcode = IRETURN;
}
else if ( type == long.class )
{
returnOpcode = LRETURN;
}
else if ( type == float.class )
{
returnOpcode = FRETURN;
}
else if ( type == double.class )
{
returnOpcode = DRETURN;
}
else
{
returnOpcode = ARETURN;
}
mv.visitInsn( returnOpcode );
}
private void visitPropertyAccessorValueRead( Class<?> type, MethodVisitor mv )
{
String methodName = null;
String methodSignature = null;
if ( type == boolean.class )
{
methodName = "readBoolean";
methodSignature = PROPERTY_ACCESSOR_READ_BOOLEAN_SIGNATURE;
}
else if ( type == byte.class )
{
methodName = "readByte";
methodSignature = PROPERTY_ACCESSOR_READ_BYTE_SIGNATURE;
}
else if ( type == char.class )
{
methodName = "readChar";
methodSignature = PROPERTY_ACCESSOR_READ_CHAR_SIGNATURE;
}
else if ( type == short.class )
{
methodName = "readShort";
methodSignature = PROPERTY_ACCESSOR_READ_SHORT_SIGNATURE;
}
else if ( type == int.class )
{
methodName = "readInt";
methodSignature = PROPERTY_ACCESSOR_READ_INT_SIGNATURE;
}
else if ( type == long.class )
{
methodName = "readLong";
methodSignature = PROPERTY_ACCESSOR_READ_LONG_SIGNATURE;
}
else if ( type == float.class )
{
methodName = "readFloat";
methodSignature = PROPERTY_ACCESSOR_READ_FLOAT_SIGNATURE;
}
else if ( type == double.class )
{
methodName = "readDouble";
methodSignature = PROPERTY_ACCESSOR_READ_DOUBLE_SIGNATURE;
}
else
{
methodName = "readObject";
methodSignature = PROPERTY_ACCESSOR_READ_OBJECT_SIGNATURE;
}
mv.visitMethodInsn( INVOKEINTERFACE, VALUEPROPERTYACCESSOR_CLASS_INTERNAL_TYPE, methodName, methodSignature );
}
private void visitPropertyAccessorValueWrite( Class<?> type, MethodVisitor mv )
{
String methodName = null;
String methodSignature = null;
if ( type == boolean.class )
{
methodName = "writeBoolean";
methodSignature = PROPERTY_ACCESSOR_WRITE_BOOLEAN_SIGNATURE;
}
else if ( type == byte.class )
{
methodName = "writeByte";
methodSignature = PROPERTY_ACCESSOR_WRITE_BYTE_SIGNATURE;
}
else if ( type == char.class )
{
methodName = "writeChar";
methodSignature = PROPERTY_ACCESSOR_WRITE_CHAR_SIGNATURE;
}
else if ( type == short.class )
{
methodName = "writeShort";
methodSignature = PROPERTY_ACCESSOR_WRITE_SHORT_SIGNATURE;
}
else if ( type == int.class )
{
methodName = "writeInt";
methodSignature = PROPERTY_ACCESSOR_WRITE_INT_SIGNATURE;
}
else if ( type == long.class )
{
methodName = "writeLong";
methodSignature = PROPERTY_ACCESSOR_WRITE_LONG_SIGNATURE;
}
else if ( type == float.class )
{
methodName = "writeFloat";
methodSignature = PROPERTY_ACCESSOR_WRITE_FLOAT_SIGNATURE;
}
else if ( type == double.class )
{
methodName = "writeDouble";
methodSignature = PROPERTY_ACCESSOR_WRITE_DOUBLE_SIGNATURE;
}
else
{
methodName = "writeObject";
methodSignature = PROPERTY_ACCESSOR_WRITE_OBJECT_SIGNATURE;
}
mv.visitMethodInsn( INVOKEINTERFACE, VALUEPROPERTYACCESSOR_CLASS_INTERNAL_TYPE, methodName, methodSignature );
}
private void visitPrimitiveAutoboxing( Class<?> type, MethodVisitor mv )
{
if ( type == boolean.class )
{
mv.visitTypeInsn( CHECKCAST, "java/lang/Boolean" );
mv.visitMethodInsn( INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z" );
}
else if ( type == byte.class )
{
mv.visitTypeInsn( CHECKCAST, "java/lang/Byte" );
mv.visitMethodInsn( INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B" );
}
else if ( type == char.class )
{
mv.visitTypeInsn( CHECKCAST, "java/lang/Character" );
mv.visitMethodInsn( INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C" );
}
else if ( type == short.class )
{
mv.visitTypeInsn( CHECKCAST, "java/lang/Short" );
mv.visitMethodInsn( INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S" );
}
else if ( type == int.class )
{
mv.visitTypeInsn( CHECKCAST, "java/lang/Integer" );
mv.visitMethodInsn( INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I" );
}
else if ( type == long.class )
{
mv.visitTypeInsn( CHECKCAST, "java/lang/Long" );
mv.visitMethodInsn( INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J" );
}
else if ( type == float.class )
{
mv.visitTypeInsn( CHECKCAST, "java/lang/Float" );
mv.visitMethodInsn( INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F" );
}
else if ( type == double.class )
{
mv.visitTypeInsn( CHECKCAST, "java/lang/Double" );
mv.visitMethodInsn( INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D" );
}
}
private void visitWrapperAutoboxing( Class<?> type, MethodVisitor mv )
{
if ( type == boolean.class )
{
mv.visitMethodInsn( INVOKESTATIC, "java/lang/Boolean", "valueOf", BOOLEAN_VALUE_OF_SIGNATURE );
}
else if ( type == byte.class )
{
mv.visitMethodInsn( INVOKESTATIC, "java/lang/Byte", "valueOf", BYTE_VALUE_OF_SIGNATURE );
}
else if ( type == char.class )
{
mv.visitMethodInsn( INVOKESTATIC, "java/lang/Character", "valueOf", CHAR_VALUE_OF_SIGNATURE );
}
else if ( type == short.class )
{
mv.visitMethodInsn( INVOKESTATIC, "java/lang/Short", "valueOf", SHORT_VALUE_OF_SIGNATURE );
}
else if ( type == int.class )
{
mv.visitMethodInsn( INVOKESTATIC, "java/lang/Integer", "valueOf", INT_VALUE_OF_SIGNATURE );
}
else if ( type == long.class )
{
mv.visitMethodInsn( INVOKESTATIC, "java/lang/Long", "valueOf", LONG_VALUE_OF_SIGNATURE );
}
else if ( type == float.class )
{
mv.visitMethodInsn( INVOKESTATIC, "java/lang/Float", "valueOf", FLOAT_VALUE_OF_SIGNATURE );
}
else if ( type == double.class )
{
mv.visitMethodInsn( INVOKESTATIC, "java/lang/Double", "valueOf", DOUBLE_VALUE_OF_SIGNATURE );
}
}
private String toFinalFieldName( String prefix, PropertyDescriptor propertyDescriptor )
{
return new StringBuilder( prefix.toUpperCase() ).append( "_" ).append( propertyDescriptor.getPropertyName().toUpperCase() ).append( "_LIGHTNING" ).toString();
}
protected void visitSystemOutPrintln( MethodVisitor mv, int stackPosition )
{
mv.visitVarInsn( ASTORE, stackPosition );
mv.visitFieldInsn( GETSTATIC, Type.getType( System.class ).getInternalName(), "out",
Type.getType( PrintStream.class ).getDescriptor() );
mv.visitVarInsn( ALOAD, stackPosition );
mv.visitMethodInsn( INVOKEVIRTUAL, Type.getType( Object.class ).getInternalName(), "toString",
"()Ljava/lang/String;" );
mv.visitMethodInsn( INVOKEVIRTUAL, Type.getType( PrintStream.class ).getInternalName(), "println",
"(Ljava/lang/String;)V" );
mv.visitVarInsn( ALOAD, stackPosition );
}
}