| /* |
| * 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: |
| // dclarke - Dynamic Persistence |
| // http://wiki.eclipse.org/EclipseLink/Development/Dynamic |
| // (https://bugs.eclipse.org/bugs/show_bug.cgi?id=200045) |
| // mnorman - tweaks to work from Ant command-line, |
| // get database properties from System, etc. |
| // |
| package org.eclipse.persistence.testing.tests.dynamic.dynamicclassloader; |
| |
| //javase imports |
| import static org.eclipse.persistence.exceptions.DynamicException.INCOMPATIBLE_DYNAMIC_CLASSWRITERS; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertSame; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import java.io.ObjectStreamException; |
| import java.io.Serializable; |
| import java.lang.reflect.Constructor; |
| |
| import org.eclipse.persistence.dynamic.DynamicClassLoader; |
| import org.eclipse.persistence.dynamic.DynamicClassWriter; |
| import org.eclipse.persistence.dynamic.DynamicEntity; |
| import org.eclipse.persistence.dynamic.EclipseLinkClassWriter; |
| import org.eclipse.persistence.exceptions.DynamicException; |
| import org.eclipse.persistence.internal.dynamic.DynamicEntityImpl; |
| import org.eclipse.persistence.internal.helper.ConversionManager; |
| import org.eclipse.persistence.internal.helper.SerializationHelper; |
| import org.junit.Test; |
| |
| public class DynamicClassLoaderTestSuite { |
| |
| public static final String PACKAGE_PREFIX = |
| DynamicClassLoaderTestSuite.class.getPackage().getName(); |
| static final String INCOMPATIBLE_CLASSNAME = Incompatible.class.getSimpleName(); |
| static final String COMPATIBLE_CLASSNAME = Compatible.class.getSimpleName(); |
| static final String MY_CLASSNAME = PACKAGE_PREFIX + ".MyClass"; |
| |
| @Test |
| public void noParentLoader() throws Exception { |
| DynamicClassLoader dcl = new DynamicClassLoader(null); |
| assertNull(dcl.getParent()); |
| } |
| |
| @Test |
| public void loadCoreClass() throws Exception { |
| DynamicClassLoader dcl = new DynamicClassLoader(null); |
| Class<?> stringClass = dcl.loadClass("java.lang.String"); |
| assertTrue("core class java.lang.String not found", String.class == stringClass); |
| } |
| |
| @Test(expected=NoClassDefFoundError.class) |
| public void createDynamicClassWithNoParentLoader() { |
| DynamicClassLoader dcl = new DynamicClassLoader(null); |
| dcl.createDynamicClass(MY_CLASSNAME); |
| } |
| |
| @Test(expected=IllegalArgumentException.class) |
| public void createIncompatibleClass() { |
| DynamicClassLoader dcl = new DynamicClassLoader(DynamicClassLoaderTestSuite.class.getClassLoader()); |
| dcl.createDynamicClass(PACKAGE_PREFIX + "." + INCOMPATIBLE_CLASSNAME); |
| } |
| |
| @Test |
| public void createCompatibleClass() { |
| DynamicClassLoader dcl = new DynamicClassLoader(DynamicClassLoaderTestSuite.class.getClassLoader()); |
| Class<?> dynamicClass = dcl.createDynamicClass(PACKAGE_PREFIX + "." + COMPATIBLE_CLASSNAME); |
| assertNotNull(dynamicClass); |
| assertSame(Compatible.class, dynamicClass); |
| } |
| |
| @SuppressWarnings("unchecked") |
| @Test |
| public void loadClass_DynamicEntityImpl() throws Exception { |
| DynamicClassLoader dcl = new DynamicClassLoader(DynamicClassLoaderTestSuite.class.getClassLoader()); |
| dcl.addClass(MY_CLASSNAME); |
| Class<?> myDynamicClass = dcl.loadClass(MY_CLASSNAME); |
| checkMyClass(dcl, myDynamicClass); |
| } |
| |
| protected void checkMyClass(DynamicClassLoader dcl, Class<?> myDynamicClass) |
| throws ClassNotFoundException, ReflectiveOperationException { |
| assertNotNull(myDynamicClass); |
| assertEquals(MY_CLASSNAME, myDynamicClass.getName()); |
| assertSame(DynamicEntityImpl.class, myDynamicClass.getSuperclass()); |
| assertSame(myDynamicClass, dcl.loadClass(MY_CLASSNAME)); |
| ConversionManager.setDefaultLoader(dcl); |
| ConversionManager.getDefaultManager().setLoader(dcl); |
| assertSame(myDynamicClass, ConversionManager.getDefaultManager().convertClassNameToClass(MY_CLASSNAME)); |
| assertSame(myDynamicClass, ConversionManager.getDefaultManager().convertObject(MY_CLASSNAME, Class.class)); |
| assertSame(myDynamicClass, ConversionManager.getDefaultLoader().loadClass(MY_CLASSNAME)); |
| assertSame(myDynamicClass, ConversionManager.loadClass(MY_CLASSNAME)); |
| Object newInstance = myDynamicClass.getConstructor().newInstance(); |
| assertNotNull("newInstance is null", newInstance); |
| Constructor<DynamicEntity>[] constructors = |
| (Constructor<DynamicEntity>[])myDynamicClass.getConstructors(); |
| assertEquals(1, constructors.length); |
| assertEquals(0, constructors[0].getParameterTypes().length); |
| } |
| |
| @SuppressWarnings("unchecked") |
| @Test |
| public void createDynamicClass_DynamicEntityImpl() throws Exception { |
| DynamicClassLoader dcl = new DynamicClassLoader(DynamicClassLoaderTestSuite.class.getClassLoader()); |
| Class<?> myDynamicClass = dcl.createDynamicClass(MY_CLASSNAME); |
| checkMyClass(dcl, myDynamicClass); |
| } |
| |
| @Test |
| public void createDynamicClass_Twice() throws Exception { |
| DynamicClassLoader dcl = new DynamicClassLoader(DynamicClassLoaderTestSuite.class.getClassLoader()); |
| |
| assertNull(dcl.getClassWriter(MY_CLASSNAME)); |
| Class<?> dynamicClass = dcl.createDynamicClass(MY_CLASSNAME); |
| |
| assertNotNull(dynamicClass); |
| assertEquals(MY_CLASSNAME, dynamicClass.getName()); |
| |
| EclipseLinkClassWriter writer = dcl.getClassWriter(MY_CLASSNAME); |
| assertNotNull(writer); |
| |
| Class<?> dynamicClass2 = dcl.createDynamicClass(MY_CLASSNAME); |
| |
| assertSame(dynamicClass, dynamicClass2); |
| |
| EclipseLinkClassWriter writer2 = dcl.getClassWriter(MY_CLASSNAME); |
| assertNotNull(writer); |
| assertSame(writer, writer2); |
| } |
| |
| @Test |
| public void defaultWriter() throws Exception { |
| DynamicClassLoader dcl = new DynamicClassLoader(DynamicClassLoaderTestSuite.class.getClassLoader()); |
| |
| assertEquals(DynamicClassWriter.class, dcl.getDefaultWriter().getClass()); |
| } |
| |
| @Test |
| public void loadClass_DefaultConstructor() throws Exception { |
| DynamicClassLoader dcl = new DynamicClassLoader(DynamicClassLoaderTestSuite.class.getClassLoader()); |
| |
| dcl.addClass(MY_CLASSNAME, DefaultConstructor.class); |
| Class<?> dynamicClass = dcl.loadClass(MY_CLASSNAME); |
| |
| assertNotNull(dynamicClass); |
| assertSame(dynamicClass, dcl.loadClass(MY_CLASSNAME)); |
| assertSame(DefaultConstructor.class, dynamicClass.getSuperclass()); |
| |
| DefaultConstructor entity = (DefaultConstructor) dynamicClass.getConstructor().newInstance(); |
| |
| assertNotNull(entity); |
| } |
| |
| @Test |
| public void loadClass_WriteReplace() throws Exception { |
| DynamicClassLoader dcl = new DynamicClassLoader(DynamicClassLoaderTestSuite.class.getClassLoader()); |
| |
| dcl.addClass(MY_CLASSNAME, WriteReplace.class); |
| Class<?> dynamicClass = dcl.loadClass(MY_CLASSNAME); |
| |
| assertNotNull(dynamicClass); |
| assertEquals(MY_CLASSNAME, dynamicClass.getName()); |
| assertSame(WriteReplace.class, dynamicClass.getSuperclass()); |
| assertSame(dynamicClass, dcl.loadClass(MY_CLASSNAME)); |
| |
| WriteReplace entity = (WriteReplace) dynamicClass.getConstructor().newInstance(); |
| |
| assertNotNull(entity); |
| |
| byte[] entityBytes = SerializationHelper.serialize(entity); |
| byte[] stringBytes = SerializationHelper.serialize(entity.getClass().getName()); |
| |
| assertEquals(stringBytes.length, entityBytes.length); |
| for (int index = 0; index < stringBytes.length; index++) { |
| assertEquals(stringBytes[index], entityBytes[index]); |
| } |
| |
| Object deserializedValue = SerializationHelper.deserialize(entityBytes); |
| |
| assertNotNull(deserializedValue); |
| assertEquals(String.class, deserializedValue.getClass()); |
| assertEquals(dynamicClass.getName(), deserializedValue); |
| } |
| |
| @Test |
| public void createDynamicClass_WriteReplace() throws Exception { |
| DynamicClassLoader dcl = new DynamicClassLoader(DynamicClassLoaderTestSuite.class.getClassLoader()); |
| |
| Class<?> dynamicClass = dcl.createDynamicClass(MY_CLASSNAME, WriteReplace.class); |
| |
| assertNotNull(dynamicClass); |
| assertEquals(MY_CLASSNAME, dynamicClass.getName()); |
| assertSame(WriteReplace.class, dynamicClass.getSuperclass()); |
| assertSame(dynamicClass, dcl.loadClass(MY_CLASSNAME)); |
| |
| WriteReplace entity = (WriteReplace) dynamicClass.getConstructor().newInstance(); |
| |
| assertNotNull(entity); |
| |
| byte[] entityBytes = SerializationHelper.serialize(entity); |
| byte[] stringBytes = SerializationHelper.serialize(entity.getClass().getName()); |
| |
| assertEquals(stringBytes.length, entityBytes.length); |
| for (int index = 0; index < stringBytes.length; index++) { |
| assertEquals(stringBytes[index], entityBytes[index]); |
| } |
| |
| Object deserializedValue = SerializationHelper.deserialize(entityBytes); |
| |
| assertNotNull(deserializedValue); |
| assertEquals(String.class, deserializedValue.getClass()); |
| assertEquals(dynamicClass.getName(), deserializedValue); |
| } |
| |
| @Test |
| public void duplicateAddClassWithSameParent() throws Exception { |
| DynamicClassLoader dcl = new DynamicClassLoader(Thread.currentThread().getContextClassLoader()); |
| |
| dcl.addClass(MY_CLASSNAME, DefaultConstructor.class); |
| Class<?> dynamicClass = dcl.loadClass(MY_CLASSNAME); |
| |
| assertNotNull(dynamicClass); |
| assertSame(dynamicClass, dcl.loadClass(MY_CLASSNAME)); |
| assertSame(DefaultConstructor.class, dynamicClass.getSuperclass()); |
| EclipseLinkClassWriter firstWriter = dcl.getClassWriter(MY_CLASSNAME); |
| DefaultConstructor entity = (DefaultConstructor) dynamicClass.getConstructor().newInstance(); |
| |
| assertNotNull(entity); |
| assertNotNull("DCL does not contain expected writer", dcl.getClassWriter(MY_CLASSNAME)); |
| |
| dcl.addClass(MY_CLASSNAME, DefaultConstructor.class); |
| EclipseLinkClassWriter secondWriter = dcl.getClassWriter(MY_CLASSNAME); |
| |
| assertSame(firstWriter, secondWriter); |
| } |
| |
| /** |
| * Verify that a second request to create a class with the same name and |
| * different parents fails. |
| */ |
| @Test |
| public void duplicateAddClassWithDifferentParent() throws Exception { |
| DynamicClassLoader dcl = new DynamicClassLoader(Thread.currentThread().getContextClassLoader()); |
| |
| dcl.addClass(MY_CLASSNAME, DefaultConstructor.class); |
| Class<?> dynamicClass = dcl.loadClass(MY_CLASSNAME); |
| |
| assertNotNull(dynamicClass); |
| assertSame(dynamicClass, dcl.loadClass(MY_CLASSNAME)); |
| assertSame(DefaultConstructor.class, dynamicClass.getSuperclass()); |
| |
| DefaultConstructor entity = (DefaultConstructor) dynamicClass.getConstructor().newInstance(); |
| |
| assertNotNull(entity); |
| assertNotNull("DCL does not contain expected writer", dcl.getClassWriter(MY_CLASSNAME)); |
| |
| try { |
| dcl.addClass(MY_CLASSNAME, WriteReplace.class); |
| } catch (DynamicException de) { |
| String errorMessage = de.getMessage(); |
| int errorCode = de.getErrorCode(); |
| |
| assertTrue("Incorrect dynamic exception", errorMessage.startsWith("\r\nException Description: Duplicate addClass request with incompatible writer:")); |
| assertEquals("Unexpected error code", INCOMPATIBLE_DYNAMIC_CLASSWRITERS, errorCode); |
| return; |
| } |
| fail("No DynamicException thrown for duplicate addClass with different parent"); |
| } |
| |
| public static class DefaultConstructor { |
| } |
| |
| public static class StringConstructor { |
| public StringConstructor(String arg) { |
| } |
| } |
| |
| public static class WriteReplace implements Serializable { |
| protected Object writeReplace() throws ObjectStreamException { |
| return getClass().getName(); |
| } |
| } |
| } |