/* * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule.runtime.core.util; import static java.lang.Thread.currentThread; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.sameInstance; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mule.runtime.core.util.ClassUtils.getSatisfiableMethods; import static org.mule.runtime.core.util.ClassUtils.withContextClassLoader; import org.mule.tck.junit4.AbstractMuleTestCase; import org.mule.tck.size.SmallTest; import org.mule.tck.testmodels.fruit.AbstractFruit; import org.mule.tck.testmodels.fruit.Apple; import org.mule.tck.testmodels.fruit.Banana; import org.mule.tck.testmodels.fruit.Fruit; import org.mule.tck.testmodels.fruit.FruitBowl; import org.mule.tck.testmodels.fruit.Kiwi; import org.mule.tck.testmodels.fruit.Orange; import org.mule.tck.testmodels.fruit.WaterMelon; import java.lang.reflect.Method; import java.net.URL; import java.util.Arrays; import java.util.Enumeration; import java.util.HashSet; import java.util.List; import java.util.Set; import org.junit.Test; @SmallTest public class ClassUtilsTestCase extends AbstractMuleTestCase { // we do not want to match these methods when looking for a service method to // invoke protected final Set<String> ignoreMethods = new HashSet<String>(Arrays.asList("equals", "getInvocationHandler")); @Test public void testIsConcrete() throws Exception { assertTrue(ClassUtils.isConcrete(Orange.class)); assertTrue(!ClassUtils.isConcrete(Fruit.class)); assertTrue(!ClassUtils.isConcrete(AbstractFruit.class)); try { ClassUtils.isConcrete(null); fail("Class cannot be null, exception should be thrown"); } catch (RuntimeException e) { // expected } } @Test public void testLoadClass() throws Exception { Class clazz = ClassUtils.loadClass("java.lang.String", getClass()); assertNotNull(clazz); assertEquals(clazz.getName(), "java.lang.String"); try { ClassUtils.loadClass("java.lang.Bing", getClass()); fail("ClassNotFoundException should be thrown"); } catch (ClassNotFoundException e) { // expected } } @Test public void testLoadPrimitiveClass() throws Exception { assertSame(ClassUtils.loadClass("boolean", getClass()), Boolean.TYPE); assertSame(ClassUtils.loadClass("byte", getClass()), Byte.TYPE); assertSame(ClassUtils.loadClass("char", getClass()), Character.TYPE); assertSame(ClassUtils.loadClass("double", getClass()), Double.TYPE); assertSame(ClassUtils.loadClass("float", getClass()), Float.TYPE); assertSame(ClassUtils.loadClass("int", getClass()), Integer.TYPE); assertSame(ClassUtils.loadClass("long", getClass()), Long.TYPE); assertSame(ClassUtils.loadClass("short", getClass()), Short.TYPE); } @Test public void testLoadClassOfType() throws Exception { Class<? extends Exception> clazz = ClassUtils.loadClass("java.lang.IllegalArgumentException", getClass(), Exception.class); assertNotNull(clazz); assertEquals(clazz.getName(), "java.lang.IllegalArgumentException"); try { ClassUtils.loadClass("java.lang.UnsupportedOperationException", getClass(), String.class); fail("IllegalArgumentException should be thrown since class is not of expected type"); } catch (IllegalArgumentException e) { // expected } } @Test public void testInstanciateClass() throws Exception { Object object = ClassUtils.instanciateClass("org.mule.tck.testmodels.fruit.Orange"); assertNotNull(object); assertTrue(object instanceof Orange); object = ClassUtils.instanciateClass("org.mule.tck.testmodels.fruit.FruitBowl", new Apple(), new Banana()); assertNotNull(object); assertTrue(object instanceof FruitBowl); FruitBowl bowl = (FruitBowl) object; assertTrue(bowl.hasApple()); assertTrue(bowl.hasBanana()); try { ClassUtils.instanciateClass("java.lang.Bing"); fail("Class does not exist, ClassNotFoundException should have been thrown"); } catch (ClassNotFoundException e) { // expected } } @Test public void testGetParameterTypes() throws Exception { FruitBowl bowl = new FruitBowl(); Class[] classes = ClassUtils.getParameterTypes(bowl, "apple"); assertNotNull(classes); assertEquals(1, classes.length); assertEquals(Apple.class, classes[0]); classes = ClassUtils.getParameterTypes(bowl, "invalid"); assertNotNull(classes); assertEquals(0, classes.length); } @Test public void testLoadingResources() throws Exception { URL resource = ClassUtils.getResource("log4j2-test.xml", getClass()); assertNotNull(resource); resource = ClassUtils.getResource("does-not-exist.properties", getClass()); assertNull(resource); } @Test public void testLoadingResourceEnumeration() throws Exception { Enumeration enumeration = ClassUtils.getResources("log4j2-test.xml", getClass()); assertNotNull(enumeration); assertTrue(enumeration.hasMoreElements()); enumeration = ClassUtils.getResources("does-not-exist.properties", getClass()); assertNotNull(enumeration); assertTrue(!enumeration.hasMoreElements()); } @Test public void testGetSatisfiableMethods() throws Exception { List methods = getSatisfiableMethods(FruitBowl.class, new Class[] {Apple.class}, true, true, ignoreMethods); assertNotNull(methods); assertEquals(2, methods.size()); methods = getSatisfiableMethods(FruitBowl.class, new Class[] {Apple.class}, false, true, ignoreMethods); assertNotNull(methods); assertEquals(0, methods.size()); // Test object param being unacceptible methods = getSatisfiableMethods(DummyObject.class, new Class[] {WaterMelon.class}, true, false, ignoreMethods); assertNotNull(methods); assertEquals(0, methods.size()); // Test object param being acceptible methods = getSatisfiableMethods(DummyObject.class, new Class[] {WaterMelon.class}, true, true, ignoreMethods); assertNotNull(methods); assertEquals(2, methods.size()); // Test object param being acceptible but not void methods = getSatisfiableMethods(DummyObject.class, new Class[] {WaterMelon.class}, false, true, ignoreMethods); assertNotNull(methods); assertEquals(1, methods.size()); assertEquals("doSomethingElse", ((Method) methods.get(0)).getName()); // Test object param being acceptible by interface Type methods = getSatisfiableMethods(FruitBowl.class, new Class[] {WaterMelon[].class}, true, true, ignoreMethods); assertNotNull(methods); assertEquals(1, methods.size()); assertEquals("setFruit", ((Method) methods.get(0)).getName()); } @Test public void testSimpleName() { simpleNameHelper("String", "foo".getClass()); simpleNameHelper("int[]", (new int[0]).getClass()); simpleNameHelper("Object[][]", (new Object[0][0]).getClass()); simpleNameHelper("null", null); } @Test public void testEqual() { Object a1 = new HashBlob(1); Object a2 = new HashBlob(1); Object b = new HashBlob(2); assertTrue(ClassUtils.equal(a1, a2)); assertTrue(ClassUtils.equal(b, b)); assertTrue(ClassUtils.equal(null, null)); assertFalse(ClassUtils.equal(a1, b)); assertFalse(ClassUtils.equal(a2, b)); assertFalse(ClassUtils.equal(null, b)); assertFalse(ClassUtils.equal(b, a1)); assertFalse(ClassUtils.equal(b, a2)); assertFalse(ClassUtils.equal(b, null)); } @Test public void testHash() { Object a = new HashBlob(1); Object b = new HashBlob(2); assertTrue(ClassUtils.hash(new Object[] {a, b, a, b}) == ClassUtils.hash(new Object[] {a, b, a, b})); assertFalse(ClassUtils.hash(new Object[] {a, b, a}) == ClassUtils.hash(new Object[] {a, b, a, b})); assertFalse(ClassUtils.hash(new Object[] {a, b, a, a}) == ClassUtils.hash(new Object[] {a, b, a, b})); assertFalse(ClassUtils.hash(new Object[] {b, a, b, a}) == ClassUtils.hash(new Object[] {a, b, a, b})); } @Test public void testClassTypesWithNullInArray() { Object[] array = new Object[] {"hello", null, "world"}; Class<?>[] classTypes = ClassUtils.getClassTypes(array); assertEquals(3, classTypes.length); assertEquals(String.class, classTypes[0]); assertEquals(null, classTypes[1]); assertEquals(String.class, classTypes[2]); } @Test public void testCompareWithNull() { Class[] c1 = new Class[] {String.class, Integer.class}; Class[] c2 = new Class[] {String.class, null}; assertFalse(ClassUtils.compare(c1, c2, true)); assertFalse(ClassUtils.compare(c2, c1, true)); } @Test public void getFieldValue() throws Exception { final int hash = hashCode(); HashBlob blob = new HashBlob(hash); assertThat(hash, equalTo(ClassUtils.getFieldValue(blob, "hash", false))); } @Test(expected = NoSuchFieldException.class) public void getUnexistentFieldValue() throws Exception { ClassUtils.getFieldValue(new HashBlob(0), "fake", false); } @Test public void getFieldValueRecursive() throws Exception { final int hash = hashCode(); HashBlob blob = new ExtendedHashBlob(hash); assertThat(hash, equalTo(ClassUtils.getFieldValue(blob, "hash", true))); } @Test(expected = NoSuchFieldException.class) public void getUnexistentFieldValueRecursive() throws Exception { ClassUtils.getFieldValue(new ExtendedHashBlob(1), "fake", true); } @Test(expected = NoSuchFieldException.class) public void getInheritedFieldValueWithoutRecurse() throws Exception { ClassUtils.getFieldValue(new ExtendedHashBlob(1), "hash", false); } @Test public void setFieldValue() throws Exception { HashBlob blob = new HashBlob(0); final int hash = hashCode(); ClassUtils.setFieldValue(blob, "hash", hash, false); assertThat(hash, equalTo(blob.getHash())); } @Test(expected = NoSuchFieldException.class) public void setUnexistentFieldValue() throws Exception { ClassUtils.setFieldValue(new HashBlob(0), "fake", 0, false); } @Test public void setFieldValueRecursive() throws Exception { HashBlob blob = new ExtendedHashBlob(0); final int hash = hashCode(); ClassUtils.setFieldValue(blob, "hash", hash, true); assertThat(hash, equalTo(blob.getHash())); } @Test(expected = NoSuchFieldException.class) public void setUnexistentFieldValueRecursive() throws Exception { ClassUtils.setFieldValue(new ExtendedHashBlob(1), "fake", 0, true); } @Test(expected = NoSuchFieldException.class) public void setInheritedFieldValueWithoutRecurse() throws Exception { ClassUtils.setFieldValue(new ExtendedHashBlob(1), "hash", 0, false); } @Test public void isInstance() { assertThat(ClassUtils.isInstance(String.class, null), is(false)); assertThat(ClassUtils.isInstance(String.class, ""), is(true)); assertThat(ClassUtils.isInstance(Fruit.class, new Apple()), is(true)); assertThat(ClassUtils.isInstance(Apple.class, new Kiwi()), is(false)); assertThat(ClassUtils.isInstance(Integer.class, 0), is(true)); assertThat(ClassUtils.isInstance(int.class, 0), is(true)); assertThat(ClassUtils.isInstance(long.class, new Long(0)), is(true)); assertThat(ClassUtils.isInstance(Double.class, new Double(0).doubleValue()), is(true)); assertThat(ClassUtils.isInstance(double.class, new Double(0).doubleValue()), is(true)); assertThat(ClassUtils.isInstance(boolean.class, true), is(true)); assertThat(ClassUtils.isInstance(boolean.class, Boolean.TRUE), is(true)); assertThat(ClassUtils.isInstance(Boolean.class, true), is(true)); assertThat(ClassUtils.isInstance(String.class, true), is(false)); assertThat(ClassUtils.isInstance(long.class, Boolean.FALSE), is(false)); } @Test public void runWithClassLoader() { final ClassLoader originalClassLoader = currentThread().getContextClassLoader(); final ClassLoader mockClassLoader = mock(ClassLoader.class); withContextClassLoader(mockClassLoader, () -> assertContextClassLoader(mockClassLoader)); assertContextClassLoader(originalClassLoader); } @Test public void returnWithClassLoader() { final String value = "Hello World!"; final ClassLoader originalClassLoader = currentThread().getContextClassLoader(); final ClassLoader mockClassLoader = mock(ClassLoader.class); String response = withContextClassLoader(mockClassLoader, () -> { assertContextClassLoader(mockClassLoader); return value; }); assertContextClassLoader(originalClassLoader); assertThat(response, is(value)); } private void assertContextClassLoader(ClassLoader mockClassLoader) { assertThat(currentThread().getContextClassLoader(), is(sameInstance(mockClassLoader))); } private void simpleNameHelper(String target, Class clazz) { assertEquals(target, ClassUtils.getSimpleName(clazz)); } private static class DummyObject { public void doSomething(Object object) { // do nothing } public Object doSomethingElse(Object object) { return object; } } private static class HashBlob { private int hash; public HashBlob(int hash) { this.hash = hash; } private int getHash() { return hash; } public int hashCode() { return hash; } public boolean equals(Object other) { if (null == other || !getClass().equals(other.getClass())) { return false; } return hash == ((HashBlob) other).hash; } } private static class ExtendedHashBlob extends HashBlob { public ExtendedHashBlob(int hash) { super(hash); } } }