/******************************************************************************* * Copyright (c) 1998, 2015 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 v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * 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.ClassWriter; import org.eclipse.persistence.internal.libraries.asm.MethodVisitor; import static org.eclipse.persistence.internal.dynamic.DynamicPropertiesManager.PROPERTIES_MANAGER_FIELD; 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.libraries.asm.Opcodes.V1_5; 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('.', '/'); ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); MethodVisitor mv; // special-case: build sub-class of XRDynamicEntityCollection if (className.endsWith(COLLECTION_WRAPPER_SUFFIX)) { cw.visit(V1_5, 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(V1_5, 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); } }