All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.babyfish.model.instrument.spi.AbstractModelReplacer Maven / Gradle / Ivy

Go to download

This tool project supports some maven plugins of BabyFish, it shouldn't used by the user directly.

The newest version!
/*
 * BabyFish, Object Model Framework for Java and JPA.
 * https://github.com/babyfish-ct/babyfish
 *
 * Copyright (c) 2008-2016, Tao Chen
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * Please visit "http://opensource.org/licenses/LGPL-3.0" to know more.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 */
package org.babyfish.model.instrument.spi;

import java.io.File;
import java.util.Collection;
import java.util.Set;

import org.babyfish.collection.LinkedHashSet;
import org.babyfish.lang.I18N;
import org.babyfish.lang.Nulls;
import org.babyfish.lang.bytecode.ASMUtils;
import org.babyfish.lang.bytecode.ScopedMethodVisitor;
import org.babyfish.lang.bytecode.ScopedMethodVisitorBuilder;
import org.babyfish.lang.instrument.IllegalClassException;
import org.babyfish.lang.instrument.bytecode.Replacer;
import org.babyfish.model.ModelType;
import org.babyfish.model.instrument.metadata.MetadataClass;
import org.babyfish.model.instrument.metadata.MetadataComparatorPart;
import org.babyfish.model.instrument.metadata.MetadataProperty;
import org.babyfish.model.metadata.ModelClass;
import org.babyfish.model.spi.ObjectModel;
import org.babyfish.model.spi.ObjectModelProvider;
import org.babyfish.org.objectweb.asm.ClassVisitor;
import org.babyfish.org.objectweb.asm.FieldVisitor;
import org.babyfish.org.objectweb.asm.MethodVisitor;
import org.babyfish.org.objectweb.asm.Opcodes;
import org.babyfish.org.objectweb.asm.Type;

/**
 * @author Tao Chen
 */
public abstract class AbstractModelReplacer extends Replacer {
    
    private MetadataClass metadataClass;
    
    private String objectModelTargetInternalName;
    
    private String objectModelContractDescriptor;
    
    private String rootObjectModelContractDescriptor;
    
    private boolean proxySupported;
    
    protected AbstractModelReplacer(
            AbstractObjectModelInstrumenter instrumenter, 
            String className, 
            File classFile,
            boolean proxySupported) {
        super(instrumenter, className, classFile);
        this.metadataClass = instrumenter.getMetadataClass(className);
        if (this.metadataClass.getModelType() != ModelType.REFERENCE) {
            proxySupported = false;
        }
        
        if (proxySupported) {
            this.objectModelTargetInternalName = 
                    this.getInternalName() + '$' + Identifiers.OBJECT_MODEL_TARGET_SIMPLE_NAME;
            this.objectModelContractDescriptor = 
                    'L' + this.getInternalName() + '$' + Identifiers.OBJECT_MODEL_CONTRACT_SIMPLE_NAME + ';';
        } else {
            this.objectModelTargetInternalName = 
                    this.getInternalName() + '$' + Identifiers.OBJECT_MODEL_CONTRACT_SIMPLE_NAME;
            this.objectModelContractDescriptor =
                    'L' + this.objectModelTargetInternalName + ';';
        }
        
        MetadataClass rootClass = this.getMetadataClass();
        while (rootClass.getSuperClass() != null) {
            rootClass = rootClass.getSuperClass();
        }
        this.rootObjectModelContractDescriptor = 
                'L' + 
                rootClass.getInternalName() + 
                '$' + 
                Identifiers.OBJECT_MODEL_CONTRACT_SIMPLE_NAME +
                ';';
        
        this.proxySupported = proxySupported;
        
        if (proxySupported) {
            this.new ObjectModelInterfaceGenerator();
            this.createObjectModelTargetGenerator();
            this.createObjectModelProxyGenerator();
        } else {
            this.createObjectModelTargetGenerator();
        }
    }
    
    public final MetadataClass getMetadataClass() {
        return this.metadataClass;
    }
    
    public final boolean isProxySupported() {
        return this.proxySupported;
    }
    
    protected void createObjectModelTargetGenerator() {
        new ObjectModelTargetGenerator(this);
    }
    
    protected void createObjectModelProxyGenerator() {}
    
    protected String[] determineMoreInterfaces() {
        return new String[] { Type.getInternalName(ObjectModelProvider.class) };
    }

    @Override
    protected ClassVisitor onCreateClassAdapter(ClassVisitor cv) {
        return new ClassAdapter(cv);
    }
    
    protected String getRuntimeModelClassImplDescriptor() {
        return ASMConstants.MODEL_CLASS_IMPL_DESCRITOR;
    }
    
    protected String getRuntimeModelPropertyImplDescriptor() {
        return ASMConstants.MODEL_PROPERTY_IMPL_DESCRIPTOR;
    }
    
    protected String[] getAdditionalModelPropertyImplConstructorArgDescriptors() {
        return null;
    }
    
    protected void loadAdditionalModelPropertyImplConstructorArgs(
            MethodVisitor mv, MetadataProperty metadataProperty) {
    }
    
    protected void visitGetObjectModelAnnotations(MethodVisitor mv) {}
    
    private void generateFields(ClassVisitor cv) {
        cv
        .visitField(
                Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL, 
                Identifiers.MODEL_CLASS_FIELD_NAME, 
                ASMConstants.MODEL_CLASS_DESCRIPTOR, 
                null,
                null
        );
        if (this.getMetadataClass().getSuperClass() == null) {
            cv
            .visitField(
                    Opcodes.ACC_PROTECTED, 
                    Identifiers.OBJECT_MODEL_FIELD_NAME, 
                    this.objectModelContractDescriptor, 
                    null, 
                    null
            )
            .visitEnd();
        }
    }

    private void generateObjectModelMethods(ClassVisitor cv) {
        this.generateCreateObjectModel(cv);
        this.generateGetObjectModel(cv);
    }

    private void generatePreClinitInsns(MethodVisitor mv) {
        this.generateInitModelClassInsns(mv);
    }
    
    private void generateInitModelClassInsns(MethodVisitor mv) {
        MetadataClass metadataClass = this.getMetadataClass();
        String runtimeModelClassImplInternalName = descToInternalName(this.getRuntimeModelClassImplDescriptor());
        String runtimeModelPropertyImplDescriptor = this.getRuntimeModelPropertyImplDescriptor();
        String runtimeModelPropertyImplInternalName = descToInternalName(runtimeModelPropertyImplDescriptor);
        
        String comparatorPartInitDescriptor = 
                "(I" 
                + ASMConstants.STRING_COMPARATOR_TYPE_DESCRIPTOR 
                + ASMConstants.NULL_COMPARATOR_TYPE_DESCRIPTOR 
                + ")V";
        StringBuilder runtimeModelPropertyImplInitDescriptorBuilder = new StringBuilder();
        runtimeModelPropertyImplInitDescriptorBuilder
        .append("(ILjava/lang/String;")
        .append(ASMConstants.PROPERTY_TYPE_DESCRIPTOR)
        .append(ASMConstants.ASSOCIATION_TYPE_DESCRIPTOR)
        .append("ZZLjava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;")
        .append(ASMConstants.DEPENDENCY_DESCRIPTOR);
        String[] additionalModelPropertyImplConstructorArgDescriptors = 
                this.getAdditionalModelPropertyImplConstructorArgDescriptors();
        if (!Nulls.isNullOrEmpty(additionalModelPropertyImplConstructorArgDescriptors)) {
            for (String desc : additionalModelPropertyImplConstructorArgDescriptors) {
                runtimeModelPropertyImplInitDescriptorBuilder.append(desc);
            }
        }
        runtimeModelPropertyImplInitDescriptorBuilder.append(")V");
        String runtimeModelPropertyImplInitDescriptor = runtimeModelPropertyImplInitDescriptorBuilder.toString();
        
        mv.visitTypeInsn(Opcodes.NEW, runtimeModelClassImplInternalName);
        mv.visitInsn(Opcodes.DUP);
        ASMUtils.visitEnumLdc(mv, metadataClass.getModelType());
        ASMUtils.visitClassLdc(mv, metadataClass.getDescriptor());
        if (metadataClass.getSuperClass() != null) {
            ASMUtils.visitClassLdc(mv, metadataClass.getSuperClass().getDescriptor());
        } else {
            mv.visitInsn(Opcodes.ACONST_NULL);
        }
        mv.visitLdcInsn(metadataClass.getDeclaredProperties().size());
        mv.visitTypeInsn(Opcodes.ANEWARRAY, runtimeModelPropertyImplInternalName);
        int propertyIndex = 0;
        for (MetadataProperty metadataProperty : metadataClass.getDeclaredProperties().values()) {
            mv.visitInsn(Opcodes.DUP);
            mv.visitLdcInsn(propertyIndex++);
            { 
                mv.visitTypeInsn(Opcodes.NEW, runtimeModelPropertyImplInternalName);
                mv.visitInsn(Opcodes.DUP);
                mv.visitLdcInsn(metadataProperty.getId());
                mv.visitLdcInsn(metadataProperty.getName());
                ASMUtils.visitEnumLdc(mv, metadataProperty.getPropertyType());
                ASMUtils.visitEnumLdc(mv, metadataProperty.getAssociationType());
                mv.visitInsn(metadataProperty.isDeferrable() ? Opcodes.ICONST_1 : Opcodes.ICONST_0);
                mv.visitInsn(metadataProperty.isMandatory() ? Opcodes.ICONST_1 : Opcodes.ICONST_0);
                ASMUtils.visitClassLdc(mv, metadataProperty.getDescriptor());
                ASMUtils.visitClassLdc(mv, metadataProperty.getStandardCollectionType());
                ASMUtils.visitClassLdc(mv, metadataProperty.getKeyDescriptor());
                ASMUtils.visitClassLdc(mv, metadataProperty.getTargetDescriptor());
                {
                    mv.visitTypeInsn(Opcodes.NEW, ASMConstants.DEPENDENCY_INTERNAL_NAME);
                    mv.visitInsn(Opcodes.DUP);
                    mv.visitLdcInsn(propertyId(metadataProperty.getIndexProperty()));
                    mv.visitLdcInsn(propertyId(metadataProperty.getKeyProperty()));
                    mv.visitLdcInsn(propertyId(metadataProperty.getReferenceProperty()));
                    mv.visitLdcInsn(propertyId(metadataProperty.getConvarianceProperty()));
                    mv.visitLdcInsn(propertyId(metadataProperty.getOppositeProperty()));
                    if (metadataProperty.getComparatorParts() == null) {
                        mv.visitInsn(Opcodes.ACONST_NULL);
                    } else {
                        mv.visitLdcInsn(metadataProperty.getComparatorParts().size());
                        mv.visitTypeInsn(Opcodes.ANEWARRAY, ASMConstants.COMPARATOR_PART_INTERNAL_NAME);
                        int partIndex = 0;
                        for (MetadataComparatorPart comparatorPart : metadataProperty.getComparatorParts()) {
                            mv.visitInsn(Opcodes.DUP);
                            mv.visitLdcInsn(partIndex++);
                            {
                                mv.visitTypeInsn(Opcodes.NEW, ASMConstants.COMPARATOR_PART_INTERNAL_NAME);
                                mv.visitInsn(Opcodes.DUP);
                                mv.visitLdcInsn(comparatorPart.getProperty().getId());
                                ASMUtils.visitEnumLdc(mv, comparatorPart.getStringComparatorType());
                                ASMUtils.visitEnumLdc(mv, comparatorPart.getNullComparatorType());
                                mv.visitMethodInsn(
                                        Opcodes.INVOKESPECIAL, 
                                        ASMConstants.COMPARATOR_PART_INTERNAL_NAME, 
                                        "", 
                                        comparatorPartInitDescriptor, 
                                        false
                                );
                            }
                            mv.visitInsn(Opcodes.AASTORE);
                        }
                    }
                    mv.visitMethodInsn(
                            Opcodes.INVOKESPECIAL, 
                            ASMConstants.DEPENDENCY_INTERNAL_NAME, 
                            "", 
                            "(IIIII[" + ASMConstants.COMPARATOR_PART_DESCRIPTOR + ")V", 
                            false
                    );
                }
                this.loadAdditionalModelPropertyImplConstructorArgs(mv, metadataProperty);
                mv.visitMethodInsn(
                        Opcodes.INVOKESPECIAL, 
                        runtimeModelPropertyImplInternalName, 
                        "", 
                        runtimeModelPropertyImplInitDescriptor,
                        false
                );
            }
            mv.visitInsn(Opcodes.AASTORE);
        }
        if (this.getMetadataClass().getModelType() != ModelType.EMBEDDABLE) {
            mv.visitInsn(Opcodes.ACONST_NULL);
        } else {
            Collection parts = 
                    this.getMetadataClass().getComparatorParts();
            mv.visitLdcInsn(parts.size());
            mv.visitTypeInsn(Opcodes.ANEWARRAY, ASMConstants.COMPARATOR_PART_INTERNAL_NAME);
            int index = 0;
            for (MetadataComparatorPart part : parts) {
                mv.visitInsn(Opcodes.DUP);
                mv.visitLdcInsn(index++);
                {
                    mv.visitTypeInsn(Opcodes.NEW, ASMConstants.COMPARATOR_PART_INTERNAL_NAME);
                    mv.visitInsn(Opcodes.DUP);
                    mv.visitLdcInsn(part.getProperty().getId());
                    ASMUtils.visitEnumLdc(mv, part.getStringComparatorType());
                    ASMUtils.visitEnumLdc(mv, part.getNullComparatorType());
                    mv.visitMethodInsn(
                            Opcodes.INVOKESPECIAL, 
                            ASMConstants.COMPARATOR_PART_INTERNAL_NAME, 
                            "", 
                            comparatorPartInitDescriptor, 
                            false
                    );
                }
                mv.visitInsn(Opcodes.AASTORE);
            }
        }
        mv.visitMethodInsn(
                Opcodes.INVOKESPECIAL, 
                runtimeModelClassImplInternalName, 
                "", 
                '(' +
                Type.getDescriptor(ModelType.class) +
                "Ljava/lang/Class;" +
                "Ljava/lang/Class;" +
                '[' + runtimeModelPropertyImplDescriptor +
                '[' + ASMConstants.COMPARATOR_PART_DESCRIPTOR +
                ")V", 
                false
        );
        mv.visitFieldInsn(
                Opcodes.PUTSTATIC, 
                this.getInternalName(), 
                Identifiers.MODEL_CLASS_FIELD_NAME, 
                ASMConstants.MODEL_CLASS_DESCRIPTOR
        );
    }
    
    private static int propertyId(MetadataProperty metadataProperty) {
        return metadataProperty != null ? metadataProperty.getId() : -1;
    }

    private void generatePreInitInsns(MethodVisitor mv) {
        
        MetadataClass metadataClass = this.getMetadataClass();
        if (metadataClass.getSuperClass() != null) {
            return;
        }
        
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitMethodInsn(
                Opcodes.INVOKEVIRTUAL, 
                metadataClass.getInternalName(), 
                Identifiers.CREATE_OBJECT_MODEL_METHOD_NAME, 
                "()" + this.objectModelContractDescriptor,
                false
        );
        mv.visitFieldInsn(
                Opcodes.PUTFIELD, 
                metadataClass.getInternalName(), 
                Identifiers.OBJECT_MODEL_FIELD_NAME,
                this.objectModelContractDescriptor
        );
    }
    
    private void generateCreateObjectModel(ClassVisitor cv) {
        MethodVisitor mv = cv.visitMethod(
                Opcodes.ACC_PROTECTED, 
                Identifiers.CREATE_OBJECT_MODEL_METHOD_NAME, 
                "()" + this.rootObjectModelContractDescriptor, 
                null,
                null
        );
        mv.visitCode();
        
        this.generateCreateObjectModelInsns(mv);
        
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }
    
    private void generateHashCodeMethod(ClassVisitor cv) {
        try (ScopedMethodVisitor mv = 
                new ScopedMethodVisitorBuilder(Opcodes.ACC_PUBLIC, "hashCode")
                .self(this.getDescriptor())
                .output("I")
                .build(cv)
        ) {
            mv.visitCode();
            
            mv.visitFieldInsn(
                    Opcodes.GETSTATIC, 
                    this.getInternalName(), 
                    Identifiers.MODEL_CLASS_FIELD_NAME, 
                    ASMConstants.MODEL_CLASS_DESCRIPTOR
            );
            mv.visitMethodInsn(
                    Opcodes.INVOKEINTERFACE, 
                    ASMConstants.MODEL_CLASS_INTERNAL_NAME, 
                    "getDefaultEqualityComparator", 
                    "()" +ASMConstants.EQUALITY_COMPARATOR_DESCRIPTOR, 
                    true
            );
            mv.load("this");
            mv.visitMethodInsn(
                    Opcodes.INVOKEINTERFACE, 
                    ASMConstants.EQUALITY_COMPARATOR_INTERNAL_NAME, 
                    "hashCode", 
                    "(Ljava/lang/Object;)I", 
                    true
            );
            mv.visitInsn(Opcodes.IRETURN);
            
            mv.visitMaxs(0, 0);
            mv.visitEnd();
        }
    }
    
    private void generateEqualsMethod(ClassVisitor cv) {
        try (ScopedMethodVisitor mv = 
                new ScopedMethodVisitorBuilder(Opcodes.ACC_PUBLIC, "equals")
                .self(this.getDescriptor())
                .parameter("obj", "Ljava/lang/Object;")
                .output("Z")
                .build(cv)
        ) {
            mv.visitCode();
            
            mv.visitFieldInsn(
                    Opcodes.GETSTATIC, 
                    this.getInternalName(), 
                    Identifiers.MODEL_CLASS_FIELD_NAME, 
                    ASMConstants.MODEL_CLASS_DESCRIPTOR
            );
            mv.visitMethodInsn(
                    Opcodes.INVOKEINTERFACE, 
                    ASMConstants.MODEL_CLASS_INTERNAL_NAME, 
                    "getDefaultEqualityComparator", 
                    "()" +ASMConstants.EQUALITY_COMPARATOR_DESCRIPTOR, 
                    true
            );
            mv.load("this");
            mv.load("obj");
            mv.visitMethodInsn(
                    Opcodes.INVOKEINTERFACE, 
                    ASMConstants.EQUALITY_COMPARATOR_INTERNAL_NAME, 
                    "equals", 
                    "(Ljava/lang/Object;Ljava/lang/Object;)Z", 
                    true
            );
            mv.visitInsn(Opcodes.IRETURN);
            
            mv.visitMaxs(0, 0);
            mv.visitEnd();
        }
    }
    
    protected void generateCreateObjectModelInsns(MethodVisitor mv) {
        mv.visitTypeInsn(Opcodes.NEW, this.objectModelTargetInternalName);
        mv.visitInsn(Opcodes.DUP);
        mv.visitFieldInsn(
                Opcodes.GETSTATIC, 
                this.getInternalName(), 
                Identifiers.MODEL_CLASS_FIELD_NAME, 
                Type.getDescriptor(ModelClass.class)
        );
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitMethodInsn(
                Opcodes.INVOKESPECIAL, 
                this.objectModelTargetInternalName, 
                "", 
                '(' + 
                Type.getDescriptor(ModelClass.class) + 
                this.getMetadataClass().getDescriptor() +
                ")V", 
                false
        );
        mv.visitInsn(Opcodes.ARETURN);
    }
    
    private void generateGetObjectModel(ClassVisitor cv) {
        if (this.getMetadataClass().getSuperClass() != null) {
            return;
        }
        
        MethodVisitor mv = cv.visitMethod(
                Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, 
                "objectModel", 
                "()" + Type.getDescriptor(ObjectModel.class), 
                null,
                null
        );
        this.visitGetObjectModelAnnotations(mv);
        mv.visitCode();
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitFieldInsn(
                Opcodes.GETFIELD, 
                this.getMetadataClass().getInternalName(), 
                Identifiers.OBJECT_MODEL_FIELD_NAME, 
                this.objectModelContractDescriptor
        );
        mv.visitInsn(Opcodes.ARETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }
    
    private static String descToInternalName(String desc) {
        return desc.substring(1, desc.length() - 1);
    }

    private class ClassAdapter extends ClassVisitor {
        
        private boolean hasClinit;
        
        private boolean hasHashCode;
        
        private boolean hasEquals;

        public ClassAdapter(ClassVisitor cv) {
            super(Opcodes.ASM5, cv);
        }

        @Override
        public void visit(
                int version, 
                int access, 
                String name, 
                String signature, 
                String superName,
                String[] interfaces) {
            
            AbstractModelReplacer that = AbstractModelReplacer.this;
            String[] moreInterfaces = that.determineMoreInterfaces();
            if (!Nulls.isNullOrEmpty(moreInterfaces)) {
                if (Nulls.isNullOrEmpty(interfaces)) {
                    interfaces = moreInterfaces;
                } else {
                    Set set = new LinkedHashSet();
                    for (String interfaze : interfaces) {
                        set.add(interfaze);
                    }
                    for (String moreInterface : moreInterfaces) {
                        set.add(moreInterface);
                    }
                    interfaces = set.toArray(new String[set.size()]);
                }
            }
            
            super.visit(version, access, name, signature, superName, interfaces);
            that.generateFields(this.cv);
        }

        @Override
        public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
            if (AbstractModelReplacer.this.metadataClass.getDeclaredProperties().containsKey(name)) {
                return null;
            }
            return super.visitField(access, name, desc, signature, value);
        }

        @Override
        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
            if ((access & Opcodes.ACC_STATIC) != 0) {
                if (name.equals("") && desc.equals("()V")) {
                    this.hasClinit = true;
                }
            } else {
                if (name.equals("hashCode") && desc.equals("()I")) {
                    this.hasHashCode = true;
                } else if (name.equals("equals") && desc.equals("(Ljava/lang/Object;)Z")) {
                    this.hasEquals = true;
                }
            }
            MethodVisitor mv = this.cv.visitMethod(access, name, desc, signature, exceptions);
            if (mv == null) {
                return null;
            }
            return new ModelMethodAdapter(
                    AbstractModelReplacer.this.proxySupported,
                    AbstractModelReplacer.this.metadataClass, 
                    access, 
                    name, 
                    desc, 
                    signature,
                    exceptions,
                    mv,
                    clinitMv -> { AbstractModelReplacer.this.generatePreClinitInsns(clinitMv); },
                    initMv -> { AbstractModelReplacer.this.generatePreInitInsns(initMv); }
            );
        }

        @Override
        public void visitEnd() {
            if (this.hasHashCode != this.hasEquals) {
                if (this.hasHashCode) {
                    throw new IllegalClassException(
                            oneIsOverridenButAnotherIsNot(
                                    AbstractModelReplacer.this.getMetadataClass().getName(), 
                                    "public int hashCode()", 
                                    "public boolean equals(Object)"
                            )
                    );
                }
                throw new IllegalClassException(
                        oneIsOverridenButAnotherIsNot(
                                AbstractModelReplacer.this.getMetadataClass().getName(), 
                                "public boolean equals(Object)",
                                "public int hashCode()"
                        )
                );
            }
            AbstractModelReplacer that = AbstractModelReplacer.this;
            that.generateObjectModelMethods(this.cv);
            if (!this.hasHashCode) {
                that.generateHashCodeMethod(cv);
                that.generateEqualsMethod(cv);
            }
            if (!this.hasClinit) {
                MethodVisitor mv = this.cv.visitMethod(
                        Opcodes.ACC_STATIC, 
                        "", 
                        "()V", 
                        null, 
                        null
                );
                mv.visitCode();
                
                AbstractModelReplacer.this.generatePreClinitInsns(mv);
                mv.visitInsn(Opcodes.RETURN);
                
                mv.visitMaxs(0, 0);
                mv.visitEnd();
            }
            super.visitEnd();
        }
    }
    
    private class ObjectModelInterfaceGenerator extends AbstractObjectModelGenerator {

        protected ObjectModelInterfaceGenerator() {
            super(AbstractModelReplacer.this, Identifiers.OBJECT_MODEL_CONTRACT_SIMPLE_NAME);
        }
        
        @Override
        protected int determineAccess() {
            return 
                    Opcodes.ACC_PROTECTED | 
                    Opcodes.ACC_STATIC | 
                    Opcodes.ACC_ABSTRACT | 
                    Opcodes.ACC_INTERFACE;
        }
        
        @Override
        protected void generate(ClassVisitor cv) {
            MetadataClass metadataClass = AbstractModelReplacer.this.metadataClass;
            cv.visit(
                    Math.max(Opcodes.V1_8, metadataClass.getBytecodeVersion()), 
                    this.determineAccess(), 
                    this.getInternalName(), 
                    null, 
                    "java/lang/Object", 
                    new String[] { 
                            metadataClass.getSuperClass() != null ?
                                    metadataClass.getSuperClass().getInternalName() + '$' + Identifiers.OBJECT_MODEL_CONTRACT_SIMPLE_NAME :
                                    ASMConstants.OBJECT_MODEL_INTERNAL_NAME 
                    }
            );
            
            this.generateEmbededComparatorStaticFields(cv);
            this.generateHashCodeScalarMethod(cv, true);
            this.generateEqualsScalarMethod(cv, true);
            this.generateCompareScalarMethod(cv, true);
            
            for (MetadataProperty metadataProperty : metadataClass.getDeclaredProperties().values()) {
                cv
                .visitMethod(
                        Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT, 
                        Identifiers.getterName(metadataProperty), 
                        "()" + metadataProperty.getDescriptor(), 
                        metadataProperty.getSignature() != null ? "()" + metadataProperty.getSignature() : null, 
                        null
                )
                .visitEnd();
                
                MethodVisitor mv = cv.visitMethod(
                        Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT, 
                        Identifiers.setterName(metadataProperty), 
                        '(' + metadataProperty.getDescriptor() + ")V", 
                        metadataProperty.getSignature() != null ? '(' + metadataProperty.getSignature() + ")V" : null, 
                        null
                );
                mv.visitParameter(metadataProperty.getName(), 0);
                mv.visitEnd();
            }
            
            MethodVisitor mv= cv.visitMethod(Opcodes.ACC_STATIC, "", "()V", null, null);
            mv.visitCode();
            this.generateInitComparatorStaticFieldInsns(mv);
            mv.visitInsn(Opcodes.RETURN);
            mv.visitMaxs(0, 0);
            mv.visitEnd();
            
            cv.visitEnd();
        }
    }
    
    @I18N
    private static native String oneIsOverridenButAnotherIsNot(
            String className,
            String overridenMethod,
            String notOverridenMethod);
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy