// Copyright (c) 2003-2014, Jodd Team (jodd.org). All Rights Reserved.
package jodd.introspector;
import jodd.bean.BeanUtil;
import jodd.introspector.tst.Abean;
import jodd.introspector.tst.Ac;
import jodd.introspector.tst.Bbean;
import jodd.introspector.tst.Bc;
import jodd.introspector.tst.Cbean;
import jodd.introspector.tst.Mojo;
import jodd.introspector.tst.One;
import jodd.introspector.tst.OneSub;
import jodd.introspector.tst.Overload;
import jodd.introspector.tst.TwoSub;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Comparator;
import static org.junit.Assert.*;
public class IntrospectorTest {
@Test
public void testBasic() {
ClassDescriptor cd = ClassIntrospector.lookup(Abean.class);
assertNotNull(cd);
PropertyDescriptor[] properties = cd.getAllPropertyDescriptors();
int c = 0;
for (PropertyDescriptor property : properties) {
if (property.isFieldOnly()) continue;
if (property.isPublic()) c++;
}
assertEquals(2, c);
Arrays.sort(properties, new Comparator<PropertyDescriptor>() {
public int compare(PropertyDescriptor o1, PropertyDescriptor o2) {
return o1.getName().compareTo(o2.getName());
}
});
PropertyDescriptor pd = properties[0];
assertEquals("fooProp", pd.getName());
assertNotNull(pd.getReadMethodDescriptor());
assertNotNull(pd.getWriteMethodDescriptor());
assertNotNull(pd.getFieldDescriptor());
pd = properties[1];
assertEquals("shared", pd.getName());
assertNull(pd.getReadMethodDescriptor());
assertNull(pd.getWriteMethodDescriptor());
assertNotNull(pd.getFieldDescriptor());
pd = properties[2];
assertEquals("something", pd.getName());
assertNotNull(pd.getReadMethodDescriptor());
assertNull(pd.getWriteMethodDescriptor());
assertNull(pd.getFieldDescriptor());
assertNotNull(cd.getPropertyDescriptor("fooProp", false));
assertNotNull(cd.getPropertyDescriptor("something", false));
assertNull(cd.getPropertyDescriptor("FooProp", false));
assertNull(cd.getPropertyDescriptor("Something", false));
assertNull(cd.getPropertyDescriptor("notExisting", false));
}
@Test
public void testExtends() {
ClassDescriptor cd = ClassIntrospector.lookup(Bbean.class);
assertNotNull(cd);
PropertyDescriptor[] properties = cd.getAllPropertyDescriptors();
int c = 0;
for (PropertyDescriptor property : properties) {
if (property.isFieldOnly()) continue;
if (property.isPublic()) c++;
}
assertEquals(2, c);
c = 0;
for (PropertyDescriptor property : properties) {
if (property.isFieldOnly()) continue;
c++;
}
assertEquals(3, c);
assertEquals(4, properties.length);
Arrays.sort(properties, new Comparator<PropertyDescriptor>() {
public int compare(PropertyDescriptor o1, PropertyDescriptor o2) {
return o1.getName().compareTo(o2.getName());
}
});
PropertyDescriptor pd = properties[0];
assertEquals("boo", pd.getName());
assertNotNull(pd.getReadMethodDescriptor());
assertNotNull(pd.getWriteMethodDescriptor());
assertNotNull(pd.getFieldDescriptor());
assertFalse(pd.isFieldOnly());
pd = properties[1];
assertEquals("fooProp", pd.getName());
assertNotNull(pd.getReadMethodDescriptor());
assertNotNull(pd.getWriteMethodDescriptor());
assertNotNull(pd.getFieldDescriptor());
assertFalse(pd.isFieldOnly());
pd = properties[2];
assertEquals("shared", pd.getName());
assertNull(pd.getReadMethodDescriptor());
assertNull(pd.getWriteMethodDescriptor());
assertNotNull(pd.getFieldDescriptor());
assertTrue(pd.isFieldOnly());
pd = properties[3];
assertEquals("something", pd.getName());
assertNotNull(pd.getReadMethodDescriptor());
assertNull(pd.getWriteMethodDescriptor());
assertNull(pd.getFieldDescriptor());
assertFalse(pd.isFieldOnly());
assertNotNull(cd.getPropertyDescriptor("fooProp", false));
assertNotNull(cd.getPropertyDescriptor("something", false));
assertNull(cd.getPropertyDescriptor("FooProp", false));
assertNull(cd.getPropertyDescriptor("Something", false));
assertNull(cd.getPropertyDescriptor("notExisting", false));
assertNotNull(cd.getPropertyDescriptor("boo", true));
assertNull(cd.getPropertyDescriptor("boo", false));
}
@Test
public void testCtors() {
ClassDescriptor cd = ClassIntrospector.lookup(Ac.class);
CtorDescriptor[] ctors = cd.getAllCtorDescriptors();
int c = 0;
for (CtorDescriptor ctor : ctors) {
if (ctor.isPublic()) c++;
}
assertEquals(1, c);
ctors = cd.getAllCtorDescriptors();
assertEquals(2, ctors.length);
assertNotNull(cd.getDefaultCtorDescriptor(true));
assertNull(cd.getDefaultCtorDescriptor(false));
Constructor ctor = cd.getCtorDescriptor(new Class[] {Integer.class}, true).getConstructor();
assertNotNull(ctor);
cd = ClassIntrospector.lookup(Bc.class);
ctors = cd.getAllCtorDescriptors();
c = 0;
for (CtorDescriptor ccc : ctors) {
if (ccc.isPublic()) c++;
}
assertEquals(1, c);
ctors = cd.getAllCtorDescriptors();
assertEquals(1, ctors.length);
assertNull(cd.getDefaultCtorDescriptor(false));
assertNull(cd.getDefaultCtorDescriptor(true));
CtorDescriptor ctorDescriptor = cd.getCtorDescriptor(new Class[] {Integer.class}, true);
assertNull(ctorDescriptor);
ctor = cd.getCtorDescriptor(new Class[] {String.class}, true).getConstructor();
assertNotNull(ctor);
}
@Test
public void testSameFieldDifferentClass() {
ClassDescriptor cd = ClassIntrospector.lookup(Abean.class);
FieldDescriptor fd = cd.getFieldDescriptor("shared", false);
assertNull(fd);
fd = cd.getFieldDescriptor("shared", true);
assertNotNull(fd);
ClassDescriptor cd2 = ClassIntrospector.lookup(Bbean.class);
FieldDescriptor fd2 = cd2.getFieldDescriptor("shared", true);
assertNotEquals(fd, fd2);
assertEquals(fd.getField(), fd2.getField());
}
@Test
public void testPropertyMatches() {
ClassDescriptor cd = ClassIntrospector.lookup(Cbean.class);
PropertyDescriptor pd;
pd = cd.getPropertyDescriptor("s1", false);
assertNull(pd);
pd = cd.getPropertyDescriptor("s1", true);
assertFalse(pd.isPublic());
assertTrue(pd.getReadMethodDescriptor().isPublic());
assertFalse(pd.getWriteMethodDescriptor().isPublic());
assertNotNull(getPropertyGetterDescriptor(cd, "s1", false));
assertNull(getPropertySetterDescriptor(cd, "s1", false));
pd = cd.getPropertyDescriptor("s2", false);
assertNull(pd);
pd = cd.getPropertyDescriptor("s2", true);
assertFalse(pd.isPublic());
assertFalse(pd.getReadMethodDescriptor().isPublic());
assertTrue(pd.getWriteMethodDescriptor().isPublic());
assertNull(getPropertyGetterDescriptor(cd, "s2", false));
assertNotNull(getPropertySetterDescriptor(cd, "s2", false));
pd = cd.getPropertyDescriptor("s3", false);
assertNotNull(pd);
pd = cd.getPropertyDescriptor("s3", true);
assertTrue(pd.isPublic());
assertTrue(pd.getReadMethodDescriptor().isPublic());
assertTrue(pd.getWriteMethodDescriptor().isPublic());
assertNotNull(getPropertyGetterDescriptor(cd, "s3", false));
assertNotNull(getPropertySetterDescriptor(cd, "s3", false));
}
@Test
public void testOverload() {
ClassDescriptor cd = ClassIntrospector.lookup(Overload.class);
PropertyDescriptor[] pds = cd.getAllPropertyDescriptors();
assertEquals(1, pds.length);
PropertyDescriptor pd = pds[0];
assertNotNull(pd.getFieldDescriptor());
assertNotNull(pd.getReadMethodDescriptor());
assertNull(pd.getWriteMethodDescriptor());
}
@Test
public void testSerialUid() {
ClassDescriptor cd = ClassIntrospector.lookup(Bbean.class);
assertNull(cd.getFieldDescriptor("serialVersionUID", true));
}
@Test
public void testStaticFieldsForProperties() {
ClassDescriptor cd = ClassIntrospector.lookup(Mojo.class);
FieldDescriptor[] fieldDescriptors = cd.getAllFieldDescriptors();
assertEquals(3, fieldDescriptors.length);
MethodDescriptor[] methodDescriptors = cd.getAllMethodDescriptors();
assertEquals(2, methodDescriptors.length);
PropertyDescriptor[] propertyDescriptor = cd.getAllPropertyDescriptors();
assertEquals(3, propertyDescriptor.length);
int count = 0;
for (PropertyDescriptor pd : propertyDescriptor) {
if (pd.isFieldOnly()) {
continue;
}
count++;
}
assertEquals(1, count);
}
@Test
public void testPropertiesOneClass() throws InvocationTargetException, IllegalAccessException {
ClassDescriptor cd = ClassIntrospector.lookup(One.class);
PropertyDescriptor[] propertyDescriptors = cd.getAllPropertyDescriptors();
assertEquals(3, propertyDescriptors.length);
assertEquals("fone", propertyDescriptors[0].getName());
assertEquals("ftwo", propertyDescriptors[1].getName());
assertEquals("not", propertyDescriptors[2].getName());
for (int i = 0; i < 3; i++) {
assertNull(propertyDescriptors[i].getWriteMethodDescriptor());
if (i != 2) {
assertNotNull(propertyDescriptors[i].getReadMethodDescriptor());
} else {
assertNull(propertyDescriptors[i].getReadMethodDescriptor());
}
assertNotNull(propertyDescriptors[i].getFieldDescriptor());
}
// change value
One one = new One();
Setter setter = propertyDescriptors[0].getSetter(true);
setter.invokeSetter(one, "one!");
assertEquals("one!", one.getFone());
// fields
FieldDescriptor[] fieldDescriptors = cd.getAllFieldDescriptors();
assertEquals(3, fieldDescriptors.length);
// beanutil
BeanUtil.setDeclaredProperty(one, "fone", "!!!");
assertEquals("!!!", one.getFone());
// change value 2
setter = propertyDescriptors[2].getSetter(true);
setter.invokeSetter(one, Long.valueOf("99"));
assertEquals(99, one.whynot());
}
@Test
public void testPropertiesOneSubClass() throws InvocationTargetException, IllegalAccessException {
ClassDescriptor cd = ClassIntrospector.lookup(OneSub.class);
PropertyDescriptor[] propertyDescriptors = cd.getAllPropertyDescriptors();
assertEquals(2, propertyDescriptors.length);
assertEquals("fone", propertyDescriptors[0].getName());
assertEquals("ftwo", propertyDescriptors[1].getName());
for (int i = 0; i < 2; i++) {
assertNull(propertyDescriptors[i].getWriteMethodDescriptor());
assertNotNull(propertyDescriptors[i].getReadMethodDescriptor());
assertNotNull(propertyDescriptors[i].getFieldDescriptor());
}
// change value
OneSub one = new OneSub();
Setter setter = propertyDescriptors[0].getSetter(true);
setter.invokeSetter(one, "one!");
assertEquals("one!", one.getFone());
// fields
FieldDescriptor[] fieldDescriptors = cd.getAllFieldDescriptors();
assertEquals(1, fieldDescriptors.length);
assertEquals("ftwo", fieldDescriptors[0].getName());
// beanutil
BeanUtil.setDeclaredProperty(one, "fone", "!!!");
assertEquals("!!!", one.getFone());
}
@Test
public void testPropertiesTwoSubClass() throws InvocationTargetException, IllegalAccessException {
ClassDescriptor cd = ClassIntrospector.lookup(TwoSub.class);
PropertyDescriptor[] propertyDescriptors = cd.getAllPropertyDescriptors();
assertEquals(2, propertyDescriptors.length);
assertEquals("fone", propertyDescriptors[0].getName());
assertEquals("ftwo", propertyDescriptors[1].getName());
for (int i = 0; i < 2; i++) {
assertNull(propertyDescriptors[i].getWriteMethodDescriptor());
assertNotNull(propertyDescriptors[i].getReadMethodDescriptor());
assertNotNull(propertyDescriptors[i].getFieldDescriptor());
}
// change value
TwoSub one = new TwoSub();
Setter setter = propertyDescriptors[0].getSetter(true);
setter.invokeSetter(one, "one!");
assertEquals("one!", one.getFone());
// fields
FieldDescriptor[] fieldDescriptors = cd.getAllFieldDescriptors();
assertEquals(1, fieldDescriptors.length);
assertEquals("ftwo", fieldDescriptors[0].getName());
// beanutil
BeanUtil.setDeclaredProperty(one, "fone", "!!!");
assertEquals("!!!", one.getFone());
}
MethodDescriptor getPropertySetterDescriptor(ClassDescriptor cd, String name, boolean declared) {
PropertyDescriptor propertyDescriptor = cd.getPropertyDescriptor(name, true);
if (propertyDescriptor != null) {
MethodDescriptor setter = propertyDescriptor.getWriteMethodDescriptor();
if ((setter != null) && setter.matchDeclared(declared)) {
return setter;
}
}
return null;
}
MethodDescriptor getPropertyGetterDescriptor(ClassDescriptor cd, String name, boolean declared) {
PropertyDescriptor propertyDescriptor = cd.getPropertyDescriptor(name, true);
if (propertyDescriptor != null) {
MethodDescriptor getter = propertyDescriptor.getReadMethodDescriptor();
if ((getter != null) && getter.matchDeclared(declared)) {
return getter;
}
}
return null;
}
}