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

org.eclipse.persistence.internal.jpa.weaving.CollectionProxyClassWriter Maven / Gradle / Ivy

There is a newer version: 5.0.0-B03
Show newest version
/*
 * Copyright (c) 2014, 2021 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

// Contributors:
//     Dmitry Kornilov - Initial implementation
package org.eclipse.persistence.internal.jpa.weaving;

import org.eclipse.persistence.dynamic.DynamicClassLoader;
import org.eclipse.persistence.dynamic.EclipseLinkClassWriter;
import org.eclipse.persistence.internal.libraries.asm.EclipseLinkASMClassWriter;
import org.eclipse.persistence.internal.libraries.asm.FieldVisitor;
import org.eclipse.persistence.internal.libraries.asm.Label;
import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
import org.eclipse.persistence.internal.libraries.asm.Opcodes;

/**
 * Generates a subclass of given collection implementing CollectionProxy interface.
 * {@link org.eclipse.persistence.jpa.rs.util.CollectionProxy}
 *
 * @author Dmitry Kornilov
 * @since EclipseLink 2.6.0
 */
public class CollectionProxyClassWriter implements EclipseLinkClassWriter, Opcodes {
    private static final String CLASS_NAME_SUFFIX = "CollectionProxy";
    private static final String INTERFACE = "org/eclipse/persistence/jpa/rs/util/CollectionProxy";

    private final String parentClassName;
    private final String entityName;
    private final String fieldName;

    /**
     * Creates a new CollectionProxyClassWriter for the given attribute of the given entity of given type.
     *
     * @param parentClassName the superclass name.
     * @param entityName entity name
     * @param fieldName entity attribute name
     */
    public CollectionProxyClassWriter(String parentClassName, String entityName, String fieldName) {
        this.parentClassName = parentClassName;
        this.entityName = entityName;
        this.fieldName = fieldName;
    }

    /**
     * Returns a class name for CollectionProxy based on parent class name and field name
     * to generate proxy for.
     * The name is constructed as _<className>_<fieldName>_RestCollectionProxy.
     *
     * @param entityName full class name (including package)
     * @param fieldName field name
     * @return Rest collection proxy name.
     */
    public static String getClassName(String entityName, String fieldName) {
        final int index = entityName.lastIndexOf('.');
        final String packageName = index >= 0 ? entityName.substring(0, index) : "";
        final String shortClassName = index >= 0 ? entityName.substring(index + 1) : entityName;
        return packageName + "._" + shortClassName + "_" + fieldName + "_" + CLASS_NAME_SUFFIX;
    }

    /**
     * Returns a class name for generated CollectionProxy.
     * {@link #getClassName(String, String)}
     *
     * @return Rest collection proxy name.
     */
    public String getClassName() {
        return getClassName(entityName, fieldName);
    }

    /**
     *  public class Proxy extends SuperType implements CollectionProxy {
     *      private List<LinkV2> links;
     *
     *      public CollectionProxy(Collection c) {
     *          super();
     *          this.addAll(c);
     *      }
     *
     *      @Override
     *      public List<LinkV2> getLinks() {
     *          return links;
     *      }
     *
     *      @Override
     *      public void setLinks(List<LinkV2> links) {
     *          this.links = links;
     *      }
     *  }
     *
     * @param loader
     * @param className
     * @return
     */
    @Override
    public byte[] writeClass(DynamicClassLoader loader, String className) {

        final EclipseLinkASMClassWriter cw = new EclipseLinkASMClassWriter(0);
        MethodVisitor mv;

        // public class Proxy extends SuperType implements CollectionProxy
        cw.visit(ACC_PUBLIC + ACC_SUPER, getASMClassName(), null, getASMParentClassName(), new String[]{INTERFACE});

        // private List links;
        final FieldVisitor fv = cw.visitField(ACC_PRIVATE, "links", "Ljava/util/List;", "Ljava/util/List;", null);
        fv.visitEnd();

        // public CollectionProxy(Collection c) {
        //     super();
        //     this.addAll(c);
        // }
        {
            mv = cw.visitMethod(ACC_PUBLIC, "", "(Ljava/util/Collection;)V", null, null);
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(15, l0);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, getASMParentClassName(), "", "()V", false);
            Label l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLineNumber(16, l1);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitMethodInsn(INVOKEVIRTUAL, getASMClassName(), "addAll", "(Ljava/util/Collection;)Z", false);
            mv.visitInsn(POP);
            Label l2 = new Label();
            mv.visitLabel(l2);
            mv.visitLineNumber(17, l2);
            mv.visitInsn(RETURN);
            Label l3 = new Label();
            mv.visitLabel(l3);
            mv.visitLocalVariable("this", "L" + getASMClassName() + ";", null, l0, l3, 0);
            mv.visitLocalVariable("c", "Ljava/util/Collection;", null, l0, l3, 1);
            mv.visitMaxs(2, 2);
            mv.visitEnd();
        }

        // @Override
        // public List getLinks() {
        //    return links;
        // }
        {
            mv = cw.visitMethod(ACC_PUBLIC, "getLinks", "()Ljava/util/List;", "()Ljava/util/List;", null);
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(21, l0);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitFieldInsn(GETFIELD, getASMClassName(), "links", "Ljava/util/List;");
            mv.visitInsn(ARETURN);
            Label l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLocalVariable("this", "L" + getASMClassName() + ";", null, l0, l1, 0);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }

        // @Override
        // public void setLinks(List links) {
        //    this.links = links;
        // }
        {
            mv = cw.visitMethod(ACC_PUBLIC, "setLinks", "(Ljava/util/List;)V", "(Ljava/util/List;)V", null);
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(26, l0);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitFieldInsn(PUTFIELD, getASMClassName(), "links", "Ljava/util/List;");
            Label l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLineNumber(27, l1);
            mv.visitInsn(RETURN);
            Label l2 = new Label();
            mv.visitLabel(l2);
            mv.visitLocalVariable("this", "L" + getASMClassName()+ ";", null, l0, l2, 0);
            mv.visitLocalVariable("links", "Ljava/util/List;", "Ljava/util/List;", l0, l2, 1);
            mv.visitMaxs(2, 2);
            mv.visitEnd();
        }

        return cw.toByteArray();
    }

    @Override
    public boolean isCompatible(EclipseLinkClassWriter writer) {
        return getParentClassName().equals(writer.getParentClassName());
    }

    @Override
    public Class getParentClass() {
        return null;
    }

    @Override
    public String getParentClassName() {
        return parentClassName;
    }

    private String getASMClassName() {
        return getClassName().replace('.', '/');
    }

    private String getASMParentClassName() {
        return parentClassName.replace('.', '/');
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy