/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.bean;
import com.liferay.portal.kernel.memory.FinalizeManager;
import com.liferay.portal.kernel.process.ClassPathUtil;
import com.liferay.portal.kernel.test.GCUtil;
import com.liferay.portal.kernel.test.ReflectionTestUtil;
import com.liferay.portal.kernel.test.rule.AggregateTestRule;
import com.liferay.portal.kernel.test.rule.CodeCoverageAssertor;
import com.liferay.portal.kernel.test.rule.NewEnv;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.test.aspects.ReflectionUtilAdvice;
import com.liferay.portal.test.rule.AdviseWith;
import com.liferay.portal.test.rule.AspectJNewEnvTestRule;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Map;
import org.junit.Assert;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
/**
* @author Shuyang Zhou
*/
public class ConstantsBeanFactoryImplTest {
@ClassRule
@Rule
public static final AggregateTestRule aggregateTestRule =
new AggregateTestRule(
CodeCoverageAssertor.INSTANCE, AspectJNewEnvTestRule.INSTANCE);
@AdviseWith(adviceClasses = {ReflectionUtilAdvice.class})
@NewEnv(type = NewEnv.Type.CLASSLOADER)
@Test
public void testClassInitializationFailure() throws Exception {
Throwable throwable = new Throwable();
ReflectionUtilAdvice.setDeclaredMethodThrowable(throwable);
try {
Class.forName(ConstantsBeanFactoryImpl.class.getName());
Assert.fail();
}
catch (ExceptionInInitializerError eiie) {
Assert.assertSame(throwable, eiie.getCause());
}
}
@NewEnv(type = NewEnv.Type.CLASSLOADER)
@Test
public void testCreateConstantsBean() throws Exception {
// Exception on create
Method defineClassMethod = ReflectionTestUtil.getAndSetFieldValue(
ConstantsBeanFactoryImpl.class, "_defineClassMethod", null);
try {
ConstantsBeanFactoryImpl.createConstantsBean(Constants.class);
Assert.fail();
}
catch (RuntimeException re) {
Throwable throwable = re.getCause();
Assert.assertSame(NullPointerException.class, throwable.getClass());
}
finally {
ReflectionTestUtil.setFieldValue(
ConstantsBeanFactoryImpl.class, "_defineClassMethod",
defineClassMethod);
}
// Normal create
ReflectionUtilAdvice.setDeclaredMethodThrowable(null);
Object constantsBean = ConstantsBeanFactoryImpl.createConstantsBean(
Constants.class);
Class<?> constantsBeanClass = constantsBean.getClass();
Assert.assertEquals(Modifier.PUBLIC, constantsBeanClass.getModifiers());
Assert.assertEquals(
Constants.class.getName() + "Bean", constantsBeanClass.getName());
Assert.assertSame(Object.class, constantsBeanClass.getSuperclass());
Method[] methods = constantsBeanClass.getDeclaredMethods();
Assert.assertEquals(Arrays.toString(methods), 12, methods.length);
Arrays.sort(
methods,
new Comparator<Method>() {
@Override
public int compare(Method method1, Method method2) {
String name1 = method1.getName();
String name2 = method2.getName();
return name1.compareTo(name2);
}
});
// public boolean getBOOLEAN_VALUE();
Method method = methods[0];
Assert.assertEquals(Modifier.PUBLIC, method.getModifiers());
Assert.assertSame(Boolean.TYPE, method.getReturnType());
Assert.assertEquals("getBOOLEAN_VALUE", method.getName());
Class<?>[] parameterTypes = method.getParameterTypes();
Assert.assertEquals(
Arrays.toString(parameterTypes), 0, parameterTypes.length);
// public byte getBYTE_VALUE();
method = methods[1];
Assert.assertEquals(Modifier.PUBLIC, method.getModifiers());
Assert.assertSame(Byte.TYPE, method.getReturnType());
Assert.assertEquals("getBYTE_VALUE", method.getName());
parameterTypes = method.getParameterTypes();
Assert.assertEquals(
Arrays.toString(parameterTypes), 0, parameterTypes.length);
// public char getCHAR_VALUE();
method = methods[2];
Assert.assertEquals(Modifier.PUBLIC, method.getModifiers());
Assert.assertSame(Character.TYPE, method.getReturnType());
Assert.assertEquals("getCHAR_VALUE", method.getName());
parameterTypes = method.getParameterTypes();
Assert.assertEquals(
Arrays.toString(parameterTypes), 0, parameterTypes.length);
// public double getDOUBLE_VALUE();
method = methods[3];
Assert.assertEquals(Modifier.PUBLIC, method.getModifiers());
Assert.assertSame(Double.TYPE, method.getReturnType());
Assert.assertEquals("getDOUBLE_VALUE", method.getName());
parameterTypes = method.getParameterTypes();
Assert.assertEquals(
Arrays.toString(parameterTypes), 0, parameterTypes.length);
// public float getFLOAT_VALUE();
method = methods[4];
Assert.assertEquals(Modifier.PUBLIC, method.getModifiers());
Assert.assertSame(Float.TYPE, method.getReturnType());
Assert.assertEquals("getFLOAT_VALUE", method.getName());
parameterTypes = method.getParameterTypes();
Assert.assertEquals(
Arrays.toString(parameterTypes), 0, parameterTypes.length);
// public int getINT_VALUE();
method = methods[5];
Assert.assertEquals(Modifier.PUBLIC, method.getModifiers());
Assert.assertSame(Integer.TYPE, method.getReturnType());
Assert.assertEquals("getINT_VALUE", method.getName());
parameterTypes = method.getParameterTypes();
Assert.assertEquals(
Arrays.toString(parameterTypes), 0, parameterTypes.length);
// public long getLONG_VALUE();
method = methods[6];
Assert.assertEquals(Modifier.PUBLIC, method.getModifiers());
Assert.assertSame(Long.TYPE, method.getReturnType());
Assert.assertEquals("getLONG_VALUE", method.getName());
parameterTypes = method.getParameterTypes();
Assert.assertEquals(
Arrays.toString(parameterTypes), 0, parameterTypes.length);
// public Object getOBJECT_VALUE();
method = methods[7];
Assert.assertEquals(Modifier.PUBLIC, method.getModifiers());
Assert.assertSame(Object.class, method.getReturnType());
Assert.assertEquals("getOBJECT_VALUE", method.getName());
parameterTypes = method.getParameterTypes();
Assert.assertEquals(
Arrays.toString(parameterTypes), 0, parameterTypes.length);
// public short getSHORT_VALUE();
method = methods[8];
Assert.assertEquals(Modifier.PUBLIC, method.getModifiers());
Assert.assertSame(Short.TYPE, method.getReturnType());
Assert.assertEquals("getSHORT_VALUE", method.getName());
parameterTypes = method.getParameterTypes();
Assert.assertEquals(
Arrays.toString(parameterTypes), 0, parameterTypes.length);
// public int get_Int(int)
method = methods[9];
Assert.assertEquals(
Modifier.PUBLIC | Modifier.STATIC, method.getModifiers());
Assert.assertSame(Integer.TYPE, method.getReturnType());
Assert.assertEquals("get_Int", method.getName());
parameterTypes = method.getParameterTypes();
Assert.assertEquals(
Arrays.toString(parameterTypes), 1, parameterTypes.length);
Assert.assertSame(int.class, parameterTypes[0]);
Assert.assertEquals(10, method.invoke(null, 10));
// public Object get_Object(Object)
method = methods[10];
Assert.assertEquals(
Modifier.PUBLIC | Modifier.STATIC, method.getModifiers());
Assert.assertSame(Object.class, method.getReturnType());
Assert.assertEquals("get_Object", method.getName());
parameterTypes = method.getParameterTypes();
Assert.assertEquals(
Arrays.toString(parameterTypes), 1, parameterTypes.length);
Assert.assertSame(Object.class, parameterTypes[0]);
Object obj = new Object();
Assert.assertSame(obj, method.invoke(null, obj));
// public void get_Void()
method = methods[11];
Assert.assertEquals(
Modifier.PUBLIC | Modifier.STATIC, method.getModifiers());
Assert.assertSame(Void.TYPE, method.getReturnType());
Assert.assertEquals("get_Void", method.getName());
parameterTypes = method.getParameterTypes();
Assert.assertEquals(
Arrays.toString(parameterTypes), 0, parameterTypes.length);
// Ensure reuse of cached generated class
Object testConstantsBean2 =
ConstantsBeanFactoryImpl.createConstantsBean(Constants.class);
Assert.assertSame(constantsBeanClass, testConstantsBean2.getClass());
}
@Test
public void testSynchronizedConstantsUpdate() throws Exception {
Object constantsBean = ConstantsBeanFactoryImpl.createConstantsBean(
Constants.class);
Class<?> constantsBeanClass = constantsBean.getClass();
Method getOBJECT_VALUEMethod = constantsBeanClass.getMethod(
"getOBJECT_VALUE");
Assert.assertSame(
Constants.OBJECT_VALUE,
getOBJECT_VALUEMethod.invoke(constantsBean));
Object newObject = new Object();
Constants.OBJECT_VALUE = newObject;
Assert.assertSame(
newObject, getOBJECT_VALUEMethod.invoke(constantsBean));
}
@Test
public void testToConstantsBean() throws Exception {
System.setProperty(
FinalizeManager.class.getName() + ".thread.enabled",
StringPool.FALSE);
// First create
String jvmClassPath = ClassPathUtil.getJVMClassPath(true);
URL[] urls = null;
try {
urls = ClassPathUtil.getClassPathURLs(jvmClassPath);
}
catch (MalformedURLException murle) {
throw new RuntimeException(murle);
}
ClassLoader classLoader1 = new URLClassLoader(urls, null);
Class<?> constantsClass1 = classLoader1.loadClass(
Constants.class.getName());
ConstantsBeanFactoryImpl constantsBeanImpl =
new ConstantsBeanFactoryImpl();
Object constantsBean1 = constantsBeanImpl.getConstantsBean(
constantsClass1);
Class<?> constantsBeanClass1 = constantsBean1.getClass();
Assert.assertSame(classLoader1, constantsBeanClass1.getClassLoader());
Map<Class<?>, ?> constantsBeans =
ConstantsBeanFactoryImpl.constantsBeans;
Assert.assertEquals(
constantsBeans.toString(), 1, constantsBeans.size());
// Hit cache
Assert.assertSame(
constantsBean1,
constantsBeanImpl.getConstantsBean(constantsClass1));
Assert.assertEquals(
constantsBeans.toString(), 1, constantsBeans.size());
// Second create
ClassLoader classLoader2 = new URLClassLoader(urls, null);
Class<?> constantsClass2 = classLoader2.loadClass(
Constants.class.getName());
Object constantsBean2 = constantsBeanImpl.getConstantsBean(
constantsClass2);
Assert.assertNotSame(constantsBean1, constantsBean2);
Assert.assertNotSame(constantsBeanClass1, constantsBean2.getClass());
Assert.assertEquals(
constantsBeans.toString(), 2, constantsBeans.size());
// Hit cache
Assert.assertSame(
constantsBean2,
constantsBeanImpl.getConstantsBean(constantsClass2));
Assert.assertEquals(
constantsBeans.toString(), 2, constantsBeans.size());
// Weak reference release key
classLoader1 = null;
constantsClass1 = null;
constantsBean1 = null;
constantsBeanClass1 = null;
GCUtil.gc(true);
ReflectionTestUtil.invoke(
FinalizeManager.class, "_pollingCleanup", new Class<?>[0]);
Assert.assertSame(
constantsBean2,
constantsBeanImpl.getConstantsBean(constantsClass2));
Assert.assertEquals(
constantsBeans.toString(), 1, constantsBeans.size());
// Weak reference release value
constantsBean2 = null;
GCUtil.gc(true);
ReflectionTestUtil.invoke(
FinalizeManager.class, "_pollingCleanup", new Class<?>[0]);
Assert.assertTrue(constantsBeans.isEmpty());
}
public static class Constants {
public static boolean BOOLEAN_VALUE = false;
public static byte BYTE_VALUE = 0;
public static char CHAR_VALUE = 'a';
public static double DOUBLE_VALUE = 0;
public static float FLOAT_VALUE = 0;
public static int INT_VALUE = 0;
public static long LONG_VALUE = 0;
public static Object OBJECT_VALUE = new Object();
public static short SHORT_VALUE = 0;
public static int get_Int(int i) {
return i;
}
public static Object get_Object(Object obj) {
return obj;
}
public static void get_Void() {
}
public Object NON_STATIC_VALUE = new Object();
protected static Object NON_PUBLIC_VALUE = new Object();
}
}