private void addProxyCollectionMethods()

in openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManagerImpl.java [920:1049]


    private void addProxyCollectionMethods(ClassWriterTracker ct, String proxyClassDef, Class type) {
        // change tracker
        {
            ct.getCw().visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_TRANSIENT,
                    "changeTracker", Type.getDescriptor(CollectionChangeTracker.class), null, null).visitEnd();
            MethodVisitor mv = ct.visitMethod(Modifier.PUBLIC, "getChangeTracker",
                    Type.getMethodDescriptor(Type.getType(ChangeTracker.class))
                    , null, null);
            mv.visitCode();
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitFieldInsn(Opcodes.GETFIELD, proxyClassDef, "changeTracker", Type.getDescriptor(CollectionChangeTracker.class));

            mv.visitInsn(Opcodes.ARETURN);
            mv.visitMaxs(-1, -1);
            mv.visitEnd();
        }

        // collection copy
        {
            Constructor cons = findCopyConstructor(type);
            if (cons == null && SortedSet.class.isAssignableFrom(type)) {
                cons = findComparatorConstructor(type);
            }
            Class[] params = (cons == null) ? new Class[0]
                    : cons.getParameterTypes();

            MethodVisitor mv = ct.visitMethod(Modifier.PUBLIC, "copy",
                    Type.getMethodDescriptor(TYPE_OBJECT, TYPE_OBJECT)
                    , null, null);
            mv.visitCode();
            mv.visitTypeInsn(Opcodes.NEW, Type.getInternalName(type));
            mv.visitInsn(Opcodes.DUP);

            if (params.length == 1) {
                mv.visitVarInsn(Opcodes.ALOAD, 1);
                if (params[0] == Comparator.class) {
                    mv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(SortedSet.class));
                    mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, Type.getInternalName(SortedSet.class), "comparator",
                            Type.getMethodDescriptor(Type.getType(Comparator.class)), true);
                }
                else {
                    // otherwise just pass the parameter
                    mv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(params[0]));
                }
            }
            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(type), "<init>",
                    Type.getMethodDescriptor(Type.VOID_TYPE, AsmHelper.getParamTypes(params)), false);

            if (params.length == 0 || params[0] == Comparator.class) {
                mv.visitInsn(Opcodes.DUP);
                mv.visitVarInsn(Opcodes.ALOAD, 1);
                mv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(Collection.class));
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(type), "addAll",
                        Type.getMethodDescriptor(Type.BOOLEAN_TYPE, Type.getType(Collection.class)), false);
                mv.visitInsn(Opcodes.POP);
            }

            mv.visitInsn(Opcodes.ARETURN);
            mv.visitMaxs(-1, -1);
            mv.visitEnd();
        }

        // element type
        {
            ct.getCw().visitField(Opcodes.ACC_PRIVATE | Opcodes.ACC_TRANSIENT,
                    "elementType", Type.getDescriptor(Class.class), null, null).visitEnd();

            MethodVisitor mv = ct.visitMethod(Modifier.PUBLIC, "getElementType",
                    Type.getMethodDescriptor(Type.getType(Class.class))
                    , null, null);
            mv.visitCode();
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitFieldInsn(Opcodes.GETFIELD, proxyClassDef, "elementType", Type.getDescriptor(Class.class));

            mv.visitInsn(Opcodes.ARETURN);
            mv.visitMaxs(-1, -1);
            mv.visitEnd();

        }

        // new instance factory
        {
            MethodVisitor mv = ct.visitMethod(Modifier.PUBLIC, "newInstance",
                    Type.getMethodDescriptor(Type.getType(ProxyCollection.class),
                            Type.getType(Class.class), Type.getType(Comparator.class), Type.BOOLEAN_TYPE, Type.BOOLEAN_TYPE)
                    , null, null);
            mv.visitCode();
            mv.visitTypeInsn(Opcodes.NEW, proxyClassDef);
            mv.visitInsn(Opcodes.DUP);

            Constructor cons = findComparatorConstructor(type);
            Class[] params = (cons == null) ? new Class[0] : cons.getParameterTypes();
            if (params.length == 1) {
                mv.visitVarInsn(Opcodes.ALOAD, 2);
            }

            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, proxyClassDef, "<init>",
                Type.getMethodDescriptor(Type.VOID_TYPE, AsmHelper.getParamTypes(params)), false);

            mv.visitVarInsn(Opcodes.ASTORE, 5);
            mv.visitVarInsn(Opcodes.ALOAD, 5);
            mv.visitVarInsn(Opcodes.ALOAD, 1);
            mv.visitFieldInsn(Opcodes.PUTFIELD, proxyClassDef, "elementType", Type.getDescriptor(Class.class));

            mv.visitVarInsn(Opcodes.ILOAD, 3);
            Label lNotTrack = new Label();
            mv.visitJumpInsn(Opcodes.IFEQ, lNotTrack);
            mv.visitVarInsn(Opcodes.ALOAD, 5);
            mv.visitTypeInsn(Opcodes.NEW, Type.getInternalName(CollectionChangeTrackerImpl.class));

            mv.visitInsn(Opcodes.DUP);
            mv.visitVarInsn(Opcodes.ALOAD, 5);

            mv.visitInsn(allowsDuplicates(type) ? Opcodes.ICONST_1 : Opcodes.ICONST_0);
            mv.visitInsn(isOrdered(type) ? Opcodes.ICONST_1 : Opcodes.ICONST_0);
            mv.visitVarInsn(Opcodes.ILOAD, 4);
            mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(CollectionChangeTrackerImpl.class), "<init>",
                    Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Collection.class),
                                             Type.BOOLEAN_TYPE, Type.BOOLEAN_TYPE, Type.BOOLEAN_TYPE),
                    false);
            mv.visitFieldInsn(Opcodes.PUTFIELD, proxyClassDef, "changeTracker", Type.getDescriptor(CollectionChangeTracker.class));

            mv.visitLabel(lNotTrack);
            mv.visitVarInsn(Opcodes.ALOAD, 5);

            mv.visitInsn(Opcodes.ARETURN);
            mv.visitMaxs(-1, -1);
            mv.visitEnd();
        }
    }