/* * Copyright (c) 2013-2014, Parallel Universe Software Co. All rights reserved. * * This program and the accompanying materials are dual-licensed under * either the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation * * or (per the licensee's choosing) * * under the terms of the GNU Lesser General Public License version 3.0 * as published by the Free Software Foundation. */ package co.paralleluniverse.data.record; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import co.paralleluniverse.asm.ClassWriter; import co.paralleluniverse.asm.MethodVisitor; import static co.paralleluniverse.asm.Opcodes.*; import co.paralleluniverse.asm.Type; /** * * @author pron */ public class DynamicGeneratedRecord<R> extends DynamicRecord<R> { private static final String DYNAMIC_GENERATED_RECORD_TYPE = Type.getInternalName(DynamicGeneratedRecord.class); private static final ClassValue<MyClassLoader> myClassLoader = new ClassValue<MyClassLoader>() { @Override protected MyClassLoader computeValue(Class<?> type) { return new MyClassLoader(type.getClassLoader()); } }; static Accessor generateAccessor(Class<?> type, Field<?, ?> field, java.lang.reflect.Field f, Method getter, Method setter) { final MyClassLoader cl = myClassLoader.get(type); final String className = accessorClassName(type, field); Class<?> accessorClass; try { accessorClass = Class.forName(className, false, cl); } catch (ClassNotFoundException e) { final byte[] classData; if (field instanceof Field.ArrayField) { if (f != null) classData = generateArrayFieldAccessor(type, field, f); else classData = generateIndexedAccessor(type, field, getter, setter); } else { if (f != null) classData = generateSimpleFieldAccessor(type, field, f); else classData = generateMethodAccessor(type, field, getter, setter); } accessorClass = cl.defineClass(className, classData); } try { final Accessor accessor = (Accessor) accessorClass.newInstance(); return accessor; } catch (IllegalAccessException | InstantiationException e) { throw new AssertionError(e); } } private static class MyClassLoader extends ClassLoader { public MyClassLoader(ClassLoader parent) { super(parent); } public Class<?> defineClass(String name, byte[] b) { return defineClass(name, b, 0, b.length); } } private static String accessorClassName(Class<?> type, Field<?, ?> field) { final String packageName = DynamicGeneratedRecord.class.getPackage().getName(); final String className = type.getSimpleName() + "$" + field.name() + "Accessor$" + Integer.toHexString(type.hashCode()); return packageName + "." + className; } private static ClassWriter generateClass(Class<?> type, Field field, String accName) { final String superName = DYNAMIC_GENERATED_RECORD_TYPE + "$" + accName; final String className = accessorClassName(type, field).replace('.', '/'); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, className, null, superName, null); cw.visitInnerClass(superName, DYNAMIC_GENERATED_RECORD_TYPE, accName, ACC_STATIC + ACC_ABSTRACT); MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, superName, "<init>", "()V", false); mv.visitInsn(RETURN); mv.visitMaxs(1, 1); mv.visitEnd(); return cw; } private static String methodSigTypeDesc(Field<?, ?> field) { if (field instanceof Field.ObjectField) return "Ljava/lang/Object;"; if (field instanceof Field.ObjectArrayField) return "[Ljava/lang/Object;"; return Type.getDescriptor(field.typeClass()); } private static String methodSigComponentTypeDesc(Field<?, ?> field) { assert field instanceof Field.ArrayField; if (field instanceof Field.ObjectArrayField) return "Ljava/lang/Object;"; return Type.getDescriptor(field.typeClass().getComponentType()); } private static byte[] generateSimpleFieldAccessor(Class<?> type, Field<?, ?> field, java.lang.reflect.Field f) { final String typeName = Type.getInternalName(type); final String fieldTypeName = Type.getInternalName(field.typeClass()); final String fieldTypeDesc = Type.getDescriptor(field.typeClass()); final String accName = accessorName(field) + "Accessor"; ClassWriter cw = generateClass(type, field, accName); MethodVisitor mv; mv = cw.visitMethod(ACC_PUBLIC, "get", "(Ljava/lang/Object;)" + methodSigTypeDesc(field), null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, typeName); mv.visitFieldInsn(GETFIELD, typeName, field.name(), fieldTypeDesc); mv.visitInsn(returnOpcode(field)); mv.visitEnd(); mv = cw.visitMethod(ACC_PUBLIC, "set", "(Ljava/lang/Object;" + methodSigTypeDesc(field) + ")V", null, null); mv.visitCode(); if (Modifier.isFinal(f.getModifiers())) { mv.visitTypeInsn(NEW, "co/paralleluniverse/data/record/ReadOnlyFieldException"); mv.visitInsn(DUP); mv.visitMethodInsn(INVOKESPECIAL, "co/paralleluniverse/data/record/ReadOnlyFieldException", "<init>", "()V", false); mv.visitInsn(ATHROW); } else { mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, typeName); mv.visitVarInsn(loadOpcode(field), 2); if (field instanceof Field.ObjectField) mv.visitTypeInsn(CHECKCAST, fieldTypeName); mv.visitFieldInsn(PUTFIELD, typeName, field.name(), fieldTypeDesc); mv.visitInsn(RETURN); } mv.visitEnd(); cw.visitEnd(); return cw.toByteArray(); } private static byte[] generateMethodAccessor(Class<?> type, Field<?, ?> field, Method getter, Method setter) { final String typeName = Type.getInternalName(type); final String fieldTypeName = Type.getInternalName(field.typeClass()); final String fieldTypeDesc = Type.getDescriptor(field.typeClass()); final String accName = accessorName(field) + "Accessor"; ClassWriter cw = generateClass(type, field, accName); MethodVisitor mv; mv = cw.visitMethod(ACC_PUBLIC, "get", "(Ljava/lang/Object;)" + methodSigTypeDesc(field), null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, typeName); mv.visitMethodInsn(INVOKEVIRTUAL, typeName, getter.getName(), Type.getMethodDescriptor(getter), false); mv.visitInsn(returnOpcode(field)); mv.visitEnd(); mv = cw.visitMethod(ACC_PUBLIC, "set", "(Ljava/lang/Object;" + methodSigTypeDesc(field) + ")V", null, null); mv.visitCode(); if (setter != null) { mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, typeName); mv.visitVarInsn(loadOpcode(field), 2); if (field instanceof Field.ObjectField) mv.visitTypeInsn(CHECKCAST, fieldTypeName); mv.visitMethodInsn(INVOKEVIRTUAL, typeName, setter.getName(), Type.getMethodDescriptor(setter), false); mv.visitInsn(RETURN); } else { mv.visitTypeInsn(NEW, Type.getInternalName(ReadOnlyFieldException.class)); mv.visitInsn(DUP); mv.visitLdcInsn(field.name); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(ReadOnlyFieldException.class), "<init>", "(Ljava/lang/String;Ljava/lang/Object;)V", false); mv.visitInsn(ATHROW); } mv.visitEnd(); cw.visitEnd(); return cw.toByteArray(); } private static byte[] generateArrayFieldAccessor(Class<?> type, Field<?, ?> field, java.lang.reflect.Field f) { final String typeName = Type.getInternalName(type); final String typeDesc = Type.getDescriptor(field.typeClass()); final String accName = accessorName(field) + "ArrayAccessor"; ClassWriter cw = generateClass(type, field, accName); MethodVisitor mv; mv = cw.visitMethod(ACC_PUBLIC, "get", "(Ljava/lang/Object;)" + methodSigTypeDesc(field), null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, typeName); mv.visitFieldInsn(GETFIELD, typeName, field.name(), typeDesc); mv.visitInsn(ARETURN); mv.visitEnd(); cw.visitEnd(); return cw.toByteArray(); } private static byte[] generateIndexedAccessor(Class<?> type, Field<?, ?> field, Method getter, Method setter) { final String typeName = Type.getInternalName(type); final String fieldComponentTypeName = Type.getInternalName(field.typeClass().getComponentType()); final String fieldTypeDesc = Type.getDescriptor(field.typeClass()); final String accName = accessorName(field) + "IndexedAccessor"; ClassWriter cw = generateClass(type, field, accName); MethodVisitor mv; mv = cw.visitMethod(ACC_PUBLIC, "get", "(Ljava/lang/Object;I)" + methodSigComponentTypeDesc(field), null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, typeName); mv.visitVarInsn(ILOAD, 2); mv.visitMethodInsn(INVOKEVIRTUAL, typeName, getter.getName(), Type.getMethodDescriptor(getter), false); mv.visitInsn(returnOpcode(field)); mv.visitEnd(); mv = cw.visitMethod(ACC_PUBLIC, "set", "(Ljava/lang/Object;I" + methodSigComponentTypeDesc(field) + ")V", null, null); mv.visitCode(); if (setter != null) { mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, typeName); mv.visitVarInsn(ILOAD, 2); mv.visitVarInsn(loadOpcode(field), 3); if (field instanceof Field.ObjectArrayField) mv.visitTypeInsn(CHECKCAST, fieldComponentTypeName); mv.visitMethodInsn(INVOKEVIRTUAL, typeName, setter.getName(), Type.getMethodDescriptor(setter), false); mv.visitInsn(RETURN); } else { mv.visitTypeInsn(NEW, Type.getInternalName(ReadOnlyFieldException.class)); mv.visitInsn(DUP); mv.visitLdcInsn(field.name); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(ReadOnlyFieldException.class), "<init>", "(Ljava/lang/String;Ljava/lang/Object;)V", false); mv.visitInsn(ATHROW); } mv.visitEnd(); cw.visitEnd(); return cw.toByteArray(); } private static String accessorName(Field field) { switch (field.type()) { case Field.BOOLEAN: case Field.BOOLEAN_ARRAY: return "Boolean"; case Field.BYTE: case Field.BYTE_ARRAY: return "Byte"; case Field.SHORT: case Field.SHORT_ARRAY: return "Short"; case Field.INT: case Field.INT_ARRAY: return "Int"; case Field.LONG: case Field.LONG_ARRAY: return "Long"; case Field.FLOAT: case Field.FLOAT_ARRAY: return "Float"; case Field.DOUBLE: case Field.DOUBLE_ARRAY: return "Double"; case Field.CHAR: case Field.CHAR_ARRAY: return "Char"; case Field.OBJECT: case Field.OBJECT_ARRAY: return "Object"; default: throw new AssertionError(); } } private static int returnOpcode(Field field) { switch (field.type()) { case Field.BOOLEAN: case Field.BOOLEAN_ARRAY: case Field.BYTE: case Field.BYTE_ARRAY: case Field.SHORT: case Field.SHORT_ARRAY: case Field.INT: case Field.INT_ARRAY: case Field.CHAR: case Field.CHAR_ARRAY: return IRETURN; case Field.LONG: case Field.LONG_ARRAY: return LRETURN; case Field.FLOAT: case Field.FLOAT_ARRAY: return FRETURN; case Field.DOUBLE: case Field.DOUBLE_ARRAY: return DRETURN; case Field.OBJECT: case Field.OBJECT_ARRAY: return ARETURN; default: throw new AssertionError(); } } private static int loadOpcode(Field field) { switch (field.type()) { case Field.BOOLEAN: case Field.BOOLEAN_ARRAY: case Field.BYTE: case Field.BYTE_ARRAY: case Field.SHORT: case Field.SHORT_ARRAY: case Field.INT: case Field.INT_ARRAY: case Field.CHAR: case Field.CHAR_ARRAY: return ILOAD; case Field.LONG: case Field.LONG_ARRAY: return LLOAD; case Field.FLOAT: case Field.FLOAT_ARRAY: return FLOAD; case Field.DOUBLE: case Field.DOUBLE_ARRAY: return DLOAD; case Field.OBJECT: case Field.OBJECT_ARRAY: return ALOAD; default: throw new AssertionError(); } } DynamicGeneratedRecord(RecordType<R> recordType, Object target) { super(recordType, target); } // protected DynamicGeneratedRecord(DynamicRecordType<R> recordType) { // super(recordType); // } @Override public boolean get(Field.BooleanField<? super R> field) { return ((BooleanAccessor) entry(field).accessor).get(obj); } @Override public void set(Field.BooleanField<? super R> field, boolean value) { ((BooleanAccessor) entry(field).accessor).set(obj, value); } @Override public byte get(Field.ByteField<? super R> field) { return ((ByteAccessor) entry(field).accessor).get(obj); } @Override public void set(Field.ByteField<? super R> field, byte value) { ((ByteAccessor) entry(field).accessor).set(obj, value); } @Override public short get(Field.ShortField<? super R> field) { return ((ShortAccessor) entry(field).accessor).get(obj); } @Override public void set(Field.ShortField<? super R> field, short value) { ((ShortAccessor) entry(field).accessor).set(obj, value); } @Override public int get(Field.IntField<? super R> field) { return ((IntAccessor) entry(field).accessor).get(obj); } @Override public void set(Field.IntField<? super R> field, int value) { ((IntAccessor) entry(field).accessor).set(obj, value); } @Override public long get(Field.LongField<? super R> field) { return ((LongAccessor) entry(field).accessor).get(obj); } @Override public void set(Field.LongField<? super R> field, long value) { ((LongAccessor) entry(field).accessor).set(obj, value); } @Override public float get(Field.FloatField<? super R> field) { return ((FloatAccessor) entry(field).accessor).get(obj); } @Override public void set(Field.FloatField<? super R> field, float value) { ((FloatAccessor) entry(field).accessor).set(obj, value); } @Override public double get(Field.DoubleField<? super R> field) { return ((DoubleAccessor) entry(field).accessor).get(obj); } @Override public void set(Field.DoubleField<? super R> field, double value) { ((DoubleAccessor) entry(field).accessor).set(obj, value); } @Override public char get(Field.CharField<? super R> field) { return ((CharAccessor) entry(field).accessor).get(obj); } @Override public void set(Field.CharField<? super R> field, char value) { ((CharAccessor) entry(field).accessor).set(obj, value); } @Override public <V> V get(Field.ObjectField<? super R, V> field) { return (V) ((ObjectAccessor) entry(field).accessor).get(obj); } @Override public <V> void set(Field.ObjectField<? super R, V> field, V value) { ((ObjectAccessor) entry(field).accessor).set(obj, value); } @Override boolean[] get(Field.BooleanArrayField<? super R> field) { final RecordType.Entry entry = entry(field); if (entry.indexed) return null; return ((BooleanArrayAccessor) entry.accessor).get(obj); } @Override public boolean get(Field.BooleanArrayField<? super R> field, int index) { final RecordType.Entry entry = entry(field); if (entry.indexed) return ((BooleanIndexedAccessor) entry.accessor).get(obj, index); else return ((BooleanArrayAccessor) entry.accessor).get(obj)[index]; } @Override public void set(Field.BooleanArrayField<? super R> field, int index, boolean value) { final RecordType.Entry entry = entry(field); if (entry.indexed) ((BooleanIndexedAccessor) entry.accessor).set(obj, index, value); else ((BooleanArrayAccessor) entry.accessor).get(obj)[index] = value; } @Override public void get(Field.BooleanArrayField<? super R> field, boolean[] target, int offset) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final BooleanIndexedAccessor accessor = ((BooleanIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) target[offset + i] = accessor.get(obj, i); } else System.arraycopy(((BooleanArrayAccessor) entry.accessor).get(obj), 0, target, offset, field.length); } @Override public void set(Field.BooleanArrayField<? super R> field, boolean[] source, int offset) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final BooleanIndexedAccessor accessor = ((BooleanIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) accessor.set(obj, i, source[offset + i]); } else System.arraycopy(source, offset, ((BooleanArrayAccessor) entry.accessor).get(obj), 0, field.length); } @Override public <S> void set(Field.BooleanArrayField<? super R> field, Record<S> source, Field.BooleanArrayField<? super S> sourceField) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final BooleanIndexedAccessor accessor = ((BooleanIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) accessor.set(obj, i, source.get(sourceField, i)); } else source.get(sourceField, ((BooleanArrayAccessor) entry.accessor).get(obj), 0); } @Override byte[] get(Field.ByteArrayField<? super R> field) { final RecordType.Entry entry = entry(field); if (entry.indexed) return null; return ((ByteArrayAccessor) entry.accessor).get(obj); } @Override public byte get(Field.ByteArrayField<? super R> field, int index) { final RecordType.Entry entry = entry(field); if (entry.indexed) return ((ByteIndexedAccessor) entry.accessor).get(obj, index); else return ((ByteArrayAccessor) entry.accessor).get(obj)[index]; } @Override public void set(Field.ByteArrayField<? super R> field, int index, byte value) { final RecordType.Entry entry = entry(field); if (entry.indexed) ((ByteIndexedAccessor) entry.accessor).set(obj, index, value); else ((ByteArrayAccessor) entry.accessor).get(obj)[index] = value; } @Override public void get(Field.ByteArrayField<? super R> field, byte[] target, int offset) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final ByteIndexedAccessor accessor = ((ByteIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) target[offset + i] = accessor.get(obj, i); } else System.arraycopy(((ByteArrayAccessor) entry.accessor).get(obj), 0, target, offset, field.length); } @Override public void set(Field.ByteArrayField<? super R> field, byte[] source, int offset) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final ByteIndexedAccessor accessor = ((ByteIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) accessor.set(obj, i, source[offset + i]); } else System.arraycopy(source, offset, ((ByteArrayAccessor) entry.accessor).get(obj), 0, field.length); } @Override public <S> void set(Field.ByteArrayField<? super R> field, Record<S> source, Field.ByteArrayField<? super S> sourceField) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final ByteIndexedAccessor accessor = ((ByteIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) accessor.set(obj, i, source.get(sourceField, i)); } else source.get(sourceField, ((ByteArrayAccessor) entry.accessor).get(obj), 0); } @Override short[] get(Field.ShortArrayField<? super R> field) { final RecordType.Entry entry = entry(field); if (entry.indexed) return null; return ((ShortArrayAccessor) entry.accessor).get(obj); } @Override public short get(Field.ShortArrayField<? super R> field, int index) { final RecordType.Entry entry = entry(field); if (entry.indexed) return ((ShortIndexedAccessor) entry.accessor).get(obj, index); else return ((ShortArrayAccessor) entry.accessor).get(obj)[index]; } @Override public void set(Field.ShortArrayField<? super R> field, int index, short value) { final RecordType.Entry entry = entry(field); if (entry.indexed) ((ShortIndexedAccessor) entry.accessor).set(obj, index, value); else ((ShortArrayAccessor) entry.accessor).get(obj)[index] = value; } @Override public void get(Field.ShortArrayField<? super R> field, short[] target, int offset) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final ShortIndexedAccessor accessor = ((ShortIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) target[offset + i] = accessor.get(obj, i); } else System.arraycopy(((ShortArrayAccessor) entry.accessor).get(obj), 0, target, offset, field.length); } @Override public void set(Field.ShortArrayField<? super R> field, short[] source, int offset) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final ShortIndexedAccessor accessor = ((ShortIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) accessor.set(obj, i, source[offset + i]); } else System.arraycopy(source, offset, ((ShortArrayAccessor) entry.accessor).get(obj), 0, field.length); } @Override public <S> void set(Field.ShortArrayField<? super R> field, Record<S> source, Field.ShortArrayField<? super S> sourceField) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final ShortIndexedAccessor accessor = ((ShortIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) accessor.set(obj, i, source.get(sourceField, i)); } else source.get(sourceField, ((ShortArrayAccessor) entry.accessor).get(obj), 0); } @Override int[] get(Field.IntArrayField<? super R> field) { final RecordType.Entry entry = entry(field); if (entry.indexed) return null; return ((IntArrayAccessor) entry.accessor).get(obj); } @Override public int get(Field.IntArrayField<? super R> field, int index) { final RecordType.Entry entry = entry(field); if (entry.indexed) return ((IntIndexedAccessor) entry.accessor).get(obj, index); else return ((IntArrayAccessor) entry.accessor).get(obj)[index]; } @Override public void set(Field.IntArrayField<? super R> field, int index, int value) { final RecordType.Entry entry = entry(field); if (entry.indexed) ((IntIndexedAccessor) entry.accessor).set(obj, index, value); else ((IntArrayAccessor) entry.accessor).get(obj)[index] = value; } @Override public void get(Field.IntArrayField<? super R> field, int[] target, int offset) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final IntIndexedAccessor accessor = ((IntIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) target[offset + i] = accessor.get(obj, i); } else System.arraycopy(((IntArrayAccessor) entry.accessor).get(obj), 0, target, offset, field.length); } @Override public void set(Field.IntArrayField<? super R> field, int[] source, int offset) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final IntIndexedAccessor accessor = ((IntIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) accessor.set(obj, i, source[offset + i]); } else System.arraycopy(source, offset, ((IntArrayAccessor) entry.accessor).get(obj), 0, field.length); } @Override public <S> void set(Field.IntArrayField<? super R> field, Record<S> source, Field.IntArrayField<? super S> sourceField) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final IntIndexedAccessor accessor = ((IntIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) accessor.set(obj, i, source.get(sourceField, i)); } else source.get(sourceField, ((IntArrayAccessor) entry.accessor).get(obj), 0); } @Override long[] get(Field.LongArrayField<? super R> field) { final RecordType.Entry entry = entry(field); if (entry.indexed) return null; return ((LongArrayAccessor) entry.accessor).get(obj); } @Override public long get(Field.LongArrayField<? super R> field, int index) { final RecordType.Entry entry = entry(field); if (entry.indexed) return ((LongIndexedAccessor) entry.accessor).get(obj, index); else return ((LongArrayAccessor) entry.accessor).get(obj)[index]; } @Override public void set(Field.LongArrayField<? super R> field, int index, long value) { final RecordType.Entry entry = entry(field); if (entry.indexed) ((LongIndexedAccessor) entry.accessor).set(obj, index, value); else ((LongArrayAccessor) entry.accessor).get(obj)[index] = value; } @Override public void get(Field.LongArrayField<? super R> field, long[] target, int offset) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final LongIndexedAccessor accessor = ((LongIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) target[offset + i] = accessor.get(obj, i); } else System.arraycopy(((LongArrayAccessor) entry.accessor).get(obj), 0, target, offset, field.length); } @Override public void set(Field.LongArrayField<? super R> field, long[] source, int offset) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final LongIndexedAccessor accessor = ((LongIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) accessor.set(obj, i, source[offset + i]); } else System.arraycopy(source, offset, ((LongArrayAccessor) entry.accessor).get(obj), 0, field.length); } @Override public <S> void set(Field.LongArrayField<? super R> field, Record<S> source, Field.LongArrayField<? super S> sourceField) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final LongIndexedAccessor accessor = ((LongIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) accessor.set(obj, i, source.get(sourceField, i)); } else source.get(sourceField, ((LongArrayAccessor) entry.accessor).get(obj), 0); } @Override float[] get(Field.FloatArrayField<? super R> field) { final RecordType.Entry entry = entry(field); if (entry.indexed) return null; return ((FloatArrayAccessor) entry.accessor).get(obj); } @Override public float get(Field.FloatArrayField<? super R> field, int index) { final RecordType.Entry entry = entry(field); if (entry.indexed) return ((FloatIndexedAccessor) entry.accessor).get(obj, index); else return ((FloatArrayAccessor) entry.accessor).get(obj)[index]; } @Override public void set(Field.FloatArrayField<? super R> field, int index, float value) { final RecordType.Entry entry = entry(field); if (entry.indexed) ((FloatIndexedAccessor) entry.accessor).set(obj, index, value); else ((FloatArrayAccessor) entry.accessor).get(obj)[index] = value; } @Override public void get(Field.FloatArrayField<? super R> field, float[] target, int offset) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final FloatIndexedAccessor accessor = ((FloatIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) target[offset + i] = accessor.get(obj, i); } else System.arraycopy(((FloatArrayAccessor) entry.accessor).get(obj), 0, target, offset, field.length); } @Override public void set(Field.FloatArrayField<? super R> field, float[] source, int offset) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final FloatIndexedAccessor accessor = ((FloatIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) accessor.set(obj, i, source[offset + i]); } else System.arraycopy(source, offset, ((FloatArrayAccessor) entry.accessor).get(obj), 0, field.length); } @Override public <S> void set(Field.FloatArrayField<? super R> field, Record<S> source, Field.FloatArrayField<? super S> sourceField) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final FloatIndexedAccessor accessor = ((FloatIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) accessor.set(obj, i, source.get(sourceField, i)); } else source.get(sourceField, ((FloatArrayAccessor) entry.accessor).get(obj), 0); } @Override double[] get(Field.DoubleArrayField<? super R> field) { final RecordType.Entry entry = entry(field); if (entry.indexed) return null; return ((DoubleArrayAccessor) entry.accessor).get(obj); } @Override public double get(Field.DoubleArrayField<? super R> field, int index) { final RecordType.Entry entry = entry(field); if (entry.indexed) return ((DoubleIndexedAccessor) entry.accessor).get(obj, index); else return ((DoubleArrayAccessor) entry.accessor).get(obj)[index]; } @Override public void set(Field.DoubleArrayField<? super R> field, int index, double value) { final RecordType.Entry entry = entry(field); if (entry.indexed) ((DoubleIndexedAccessor) entry.accessor).set(obj, index, value); else ((DoubleArrayAccessor) entry.accessor).get(obj)[index] = value; } @Override public void get(Field.DoubleArrayField<? super R> field, double[] target, int offset) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final DoubleIndexedAccessor accessor = ((DoubleIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) target[offset + i] = accessor.get(obj, i); } else System.arraycopy(((DoubleArrayAccessor) entry.accessor).get(obj), 0, target, offset, field.length); } @Override public void set(Field.DoubleArrayField<? super R> field, double[] source, int offset) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final DoubleIndexedAccessor accessor = ((DoubleIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) accessor.set(obj, i, source[offset + i]); } else System.arraycopy(source, offset, ((DoubleArrayAccessor) entry.accessor).get(obj), 0, field.length); } @Override public <S> void set(Field.DoubleArrayField<? super R> field, Record<S> source, Field.DoubleArrayField<? super S> sourceField) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final DoubleIndexedAccessor accessor = ((DoubleIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) accessor.set(obj, i, source.get(sourceField, i)); } else source.get(sourceField, ((DoubleArrayAccessor) entry.accessor).get(obj), 0); } @Override char[] get(Field.CharArrayField<? super R> field) { final RecordType.Entry entry = entry(field); if (entry.indexed) return null; return ((CharArrayAccessor) entry.accessor).get(obj); } @Override public char get(Field.CharArrayField<? super R> field, int index) { final RecordType.Entry entry = entry(field); if (entry.indexed) return ((CharIndexedAccessor) entry.accessor).get(obj, index); else return ((CharArrayAccessor) entry.accessor).get(obj)[index]; } @Override public void set(Field.CharArrayField<? super R> field, int index, char value) { final RecordType.Entry entry = entry(field); if (entry.indexed) ((CharIndexedAccessor) entry.accessor).set(obj, index, value); else ((CharArrayAccessor) entry.accessor).get(obj)[index] = value; } @Override public void get(Field.CharArrayField<? super R> field, char[] target, int offset) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final CharIndexedAccessor accessor = ((CharIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) target[offset + i] = accessor.get(obj, i); } else System.arraycopy(((CharArrayAccessor) entry.accessor).get(obj), 0, target, offset, field.length); } @Override public void set(Field.CharArrayField<? super R> field, char[] source, int offset) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final CharIndexedAccessor accessor = ((CharIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) accessor.set(obj, i, source[offset + i]); } else System.arraycopy(source, offset, ((CharArrayAccessor) entry.accessor).get(obj), 0, field.length); } @Override public <S> void set(Field.CharArrayField<? super R> field, Record<S> source, Field.CharArrayField<? super S> sourceField) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final CharIndexedAccessor accessor = ((CharIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) accessor.set(obj, i, source.get(sourceField, i)); } else source.get(sourceField, ((CharArrayAccessor) entry.accessor).get(obj), 0); } @Override <V> V[] get(Field.ObjectArrayField<? super R, V> field) { final RecordType.Entry entry = entry(field); if (entry.indexed) return null; return (V[]) ((ObjectArrayAccessor) entry.accessor).get(obj); } @Override public <V> V get(Field.ObjectArrayField<? super R, V> field, int index) { final RecordType.Entry entry = entry(field); if (entry.indexed) return (V) ((ObjectIndexedAccessor) entry.accessor).get(obj, index); else return (V) ((ObjectArrayAccessor) entry.accessor).get(obj)[index]; } @Override public <V> void set(Field.ObjectArrayField<? super R, V> field, int index, V value) { final RecordType.Entry entry = entry(field); if (entry.indexed) ((ObjectIndexedAccessor) entry.accessor).set(obj, index, value); else ((ObjectArrayAccessor) entry.accessor).get(obj)[index] = value; } @Override public <V> void get(Field.ObjectArrayField<? super R, V> field, V[] target, int offset) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final ObjectIndexedAccessor accessor = ((ObjectIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) target[offset + i] = (V) accessor.get(obj, i); } else System.arraycopy(((ObjectArrayAccessor) entry.accessor).get(obj), 0, target, offset, field.length); } @Override public <V> void set(Field.ObjectArrayField<? super R, V> field, V[] source, int offset) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final ObjectIndexedAccessor accessor = ((ObjectIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) accessor.set(obj, i, source[offset + i]); } else System.arraycopy(source, offset, ((ObjectArrayAccessor) entry.accessor).get(obj), 0, field.length); } @Override public <S, V> void set(Field.ObjectArrayField<? super R, V> field, Record<S> source, Field.ObjectArrayField<? super S, V> sourceField) { final RecordType.Entry entry = entry(field); if (entry.indexed) { final ObjectIndexedAccessor accessor = ((ObjectIndexedAccessor) entry.accessor); for (int i = 0; i < field.length; i++) accessor.set(obj, i, source.get(sourceField, i)); } else source.get(sourceField, (V[]) ((ObjectArrayAccessor) entry.accessor).get(obj), 0); } public static abstract class Accessor { } public static abstract class BooleanAccessor extends Accessor { public abstract boolean get(Object target); public abstract void set(Object target, boolean value); } public static abstract class BooleanArrayAccessor extends Accessor { public abstract boolean[] get(Object target); } public static abstract class BooleanIndexedAccessor extends Accessor { public abstract boolean get(Object target, int index); public abstract void set(Object target, int index, boolean value); } public static abstract class ByteAccessor extends Accessor { public abstract byte get(Object target); public abstract void set(Object target, byte value); } public static abstract class ByteArrayAccessor extends Accessor { public abstract byte[] get(Object target); } public static abstract class ByteIndexedAccessor extends Accessor { public abstract byte get(Object target, int index); public abstract void set(Object target, int index, byte value); } public static abstract class ShortAccessor extends Accessor { public abstract short get(Object target); public abstract void set(Object target, short value); } public static abstract class ShortArrayAccessor extends Accessor { public abstract short[] get(Object target); } public static abstract class ShortIndexedAccessor extends Accessor { public abstract short get(Object target, int index); public abstract void set(Object target, int index, short value); } public static abstract class IntAccessor extends Accessor { public abstract int get(Object target); public abstract void set(Object target, int value); } public static abstract class IntArrayAccessor extends Accessor { public abstract int[] get(Object target); } public static abstract class IntIndexedAccessor extends Accessor { public abstract int get(Object target, int index); public abstract void set(Object target, int index, int value); } public static abstract class LongAccessor extends Accessor { public abstract long get(Object target); public abstract void set(Object target, long value); } public static abstract class LongArrayAccessor extends Accessor { public abstract long[] get(Object target); } public static abstract class LongIndexedAccessor extends Accessor { public abstract long get(Object target, int index); public abstract void set(Object target, int index, long value); } public static abstract class FloatAccessor extends Accessor { public abstract float get(Object target); public abstract void set(Object target, float value); } public static abstract class FloatArrayAccessor extends Accessor { public abstract float[] get(Object target); } public static abstract class FloatIndexedAccessor extends Accessor { public abstract float get(Object target, int index); public abstract void set(Object target, int index, float value); } public static abstract class DoubleAccessor extends Accessor { public abstract double get(Object target); public abstract void set(Object target, double value); } public static abstract class DoubleArrayAccessor extends Accessor { public abstract double[] get(Object target); } public static abstract class DoubleIndexedAccessor extends Accessor { public abstract double get(Object target, int index); public abstract void set(Object target, int index, double value); } public static abstract class CharAccessor extends Accessor { public abstract char get(Object target); public abstract void set(Object target, char value); } public static abstract class CharArrayAccessor extends Accessor { public abstract char[] get(Object target); } public static abstract class CharIndexedAccessor extends Accessor { public abstract char get(Object target, int index); public abstract void set(Object target, int index, char value); } public static abstract class ObjectAccessor extends Accessor { public abstract Object get(Object target); public abstract void set(Object target, Object value); } public static abstract class ObjectArrayAccessor extends Accessor { public abstract Object[] get(Object target); } public static abstract class ObjectIndexedAccessor extends Accessor { public abstract Object get(Object target, int index); public abstract void set(Object target, int index, Object value); } }