org.eclipse.persistence.internal.jpa.weaving.CollectionProxyClassWriter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eclipselink Show documentation
Show all versions of eclipselink Show documentation
EclipseLink build based upon Git transaction f2b9fc5
/*
* 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('.', '/');
}
}