blob: db5bd483bd485ee7eccd20dd26a329dfd8c78eb9 [file] [log] [blame]
/*
* Copyright (c) 1998, 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:
// mnorman - convert DBWS to use new EclipseLink public Dynamic Persistence APIs
package org.eclipse.persistence.internal.xr;
//javase imports
//EclipseLink imports
import org.eclipse.persistence.dynamic.DynamicClassLoader;
import org.eclipse.persistence.dynamic.DynamicClassWriter;
import org.eclipse.persistence.internal.libraries.asm.MethodVisitor;
import static org.eclipse.persistence.internal.dynamic.DynamicPropertiesManager.PROPERTIES_MANAGER_FIELD;
import org.eclipse.persistence.internal.libraries.asm.EclipseLinkASMClassWriter;
import static org.eclipse.persistence.internal.libraries.asm.Opcodes.ACC_PUBLIC;
import static org.eclipse.persistence.internal.libraries.asm.Opcodes.ACC_STATIC;
import static org.eclipse.persistence.internal.libraries.asm.Opcodes.ACC_SUPER;
import static org.eclipse.persistence.internal.libraries.asm.Opcodes.ALOAD;
import static org.eclipse.persistence.internal.libraries.asm.Opcodes.ARETURN;
import static org.eclipse.persistence.internal.libraries.asm.Opcodes.DUP;
import static org.eclipse.persistence.internal.libraries.asm.Opcodes.GETSTATIC;
import static org.eclipse.persistence.internal.libraries.asm.Opcodes.INVOKESPECIAL;
import static org.eclipse.persistence.internal.libraries.asm.Opcodes.NEW;
import static org.eclipse.persistence.internal.libraries.asm.Opcodes.PUTSTATIC;
import static org.eclipse.persistence.internal.libraries.asm.Opcodes.RETURN;
import static org.eclipse.persistence.internal.xr.XRDynamicClassLoader.COLLECTION_WRAPPER_SUFFIX;
/**
* <p>
* <b>INTERNAL:</b> XRClassWriter uses ASM to dynamically generate subclasses of
* {@link XRDynamicEntity}
*
* @author Mike Norman - michael.norman@oracle.com
* @since EclipseLink 1.x
*/
public class XRClassWriter extends DynamicClassWriter {
static final String XR_DYNAMIC_ENTITY_CLASSNAME_SLASHES = XRDynamicEntity.class.getName().replace('.', '/');
static final String XR_DYNAMIC_ENTITY_COLLECTION_CLASSNAME_SLASHES = XRDynamicEntity_CollectionWrapper.class.getName().replace('.', '/');
static final String XR_DYNAMIC_PROPERTIES_MANAGER_CLASSNAME_SLASHES = XRDynamicPropertiesManager.class.getName().replace('.', '/');
public XRClassWriter() {
super();
}
/*
* Pattern is as follows: <pre> public class Foo extends XRDynamicEntity {
* public static XRDynamicPropertiesManager DPM = new
* XRDynamicPropertiesManager(); public Foo() { super(); } public
* XRDynamicPropertiesManager fetchPropertiesManager() { return DPM; } }
*
* later on, the DPM field is populated: XRDynamicEntity newInstance =
* fooClz.newInstance(); XRDynamicPropertiesManager dpm =
* newInstance.getPropertiesManager(); Set<String> propertyNames = new
* HashSet<String(); propertyNames.add("prop1"); propertyNames.add("prop2");
* dpm.setPropertiesNameSet(propertyNames); </pre>
*/
@Override
public byte[] writeClass(DynamicClassLoader loader, String className) throws ClassNotFoundException {
String classNameAsSlashes = className.replace('.', '/');
EclipseLinkASMClassWriter cw = new EclipseLinkASMClassWriter();
MethodVisitor mv;
// special-case: build sub-class of XRDynamicEntityCollection
if (className.endsWith(COLLECTION_WRAPPER_SUFFIX)) {
cw.visit(ACC_PUBLIC + ACC_SUPER, classNameAsSlashes, null, XR_DYNAMIC_ENTITY_COLLECTION_CLASSNAME_SLASHES, null);
mv = cw.visitMethod(ACC_PUBLIC, INIT, "()V", null, null);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, XR_DYNAMIC_ENTITY_COLLECTION_CLASSNAME_SLASHES, INIT, "()V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
} else {
// public class Foo extends XRDynamicEntity {
cw.visit(ACC_PUBLIC + ACC_SUPER, classNameAsSlashes, null, XR_DYNAMIC_ENTITY_CLASSNAME_SLASHES, null);
// public static XRDynamicPropertiesManager DPM = new
// XRDynamicPropertiesManager();
cw.visitField(ACC_PUBLIC + ACC_STATIC, PROPERTIES_MANAGER_FIELD, "L" + XR_DYNAMIC_PROPERTIES_MANAGER_CLASSNAME_SLASHES + ";", null, null);
mv = cw.visitMethod(ACC_STATIC, CLINIT, "()V", null, null);
mv.visitTypeInsn(NEW, XR_DYNAMIC_PROPERTIES_MANAGER_CLASSNAME_SLASHES);
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, XR_DYNAMIC_PROPERTIES_MANAGER_CLASSNAME_SLASHES, INIT, "()V", false);
mv.visitFieldInsn(PUTSTATIC, classNameAsSlashes, PROPERTIES_MANAGER_FIELD, "L" + XR_DYNAMIC_PROPERTIES_MANAGER_CLASSNAME_SLASHES + ";");
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
// public Foo() {
// super();
// }
mv = cw.visitMethod(ACC_PUBLIC, INIT, "()V", null, null);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, XR_DYNAMIC_ENTITY_CLASSNAME_SLASHES, INIT, "()V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
// public XRDynamicPropertiesManager fetchPropertiesManager() {
mv = cw.visitMethod(ACC_PUBLIC, "fetchPropertiesManager", "()L" + XR_DYNAMIC_PROPERTIES_MANAGER_CLASSNAME_SLASHES + ";", null, null);
mv.visitFieldInsn(GETSTATIC, classNameAsSlashes, PROPERTIES_MANAGER_FIELD, "L" + XR_DYNAMIC_PROPERTIES_MANAGER_CLASSNAME_SLASHES + ";");
mv.visitInsn(ARETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
}
@Override
protected boolean verify(Class<?> dynamicClass, ClassLoader loader) throws ClassNotFoundException {
return dynamicClass != null && XRDynamicEntity.class.isAssignableFrom(dynamicClass);
}
}