Added utility method to return all declared super class fields
This commit is contained in:
parent
eac41eec12
commit
1bc97d88ee
6 changed files with 179 additions and 60 deletions
|
|
@ -28,12 +28,12 @@ import java.lang.reflect.Field;
|
|||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class include some utility functions for classes
|
||||
*
|
||||
* User: Ziver
|
||||
*/
|
||||
public class ClassUtil {
|
||||
/** A Set that contains possible wrapper objects for primitives **/
|
||||
|
|
@ -217,4 +217,31 @@ public class ClassUtil {
|
|||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Traverses the class hierarchy and collects all fields.
|
||||
*
|
||||
* @param clazz is the class to return fields from.
|
||||
* @return a List including all fields contained from the class and its super classes.
|
||||
*/
|
||||
public static List<Field> getAllDeclaredFields(Class<?> clazz) {
|
||||
return getAllDeclaredFields(clazz, Object.class);
|
||||
}
|
||||
/**
|
||||
* Traverses the class hierarchy and collects all fields.
|
||||
*
|
||||
* @param clazz is the class to return fields from.
|
||||
* @param upToClass a top limit class where traversal will end not including fields from this class.
|
||||
* @return a List including all fields contained from the class and its super classes.
|
||||
*/
|
||||
public static List<Field> getAllDeclaredFields(Class<?> clazz, Class<?> upToClass) {
|
||||
List<Field> fields = new ArrayList<>();
|
||||
|
||||
for (Class<?> currentClass = clazz; currentClass != upToClass; currentClass = currentClass.getSuperclass()) {
|
||||
Collections.addAll(fields, currentClass.getDeclaredFields());
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import zutil.ClassUtil;
|
|||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -53,7 +54,6 @@ class DBBeanConfig{
|
|||
private DBBeanConfig() { }
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return the configuration object for the specified class
|
||||
*/
|
||||
|
|
@ -66,21 +66,29 @@ class DBBeanConfig{
|
|||
/**
|
||||
* Caches the fields
|
||||
*/
|
||||
private static void initBeanConfig(Class<? extends DBBean> c) {
|
||||
private static void initBeanConfig(Class<? extends DBBean> clazz) {
|
||||
DBBeanConfig config = new DBBeanConfig();
|
||||
|
||||
// Find the table name
|
||||
DBBean.DBTable tableAnn = c.getAnnotation(DBBean.DBTable.class);
|
||||
|
||||
DBBean.DBTable tableAnn = clazz.getAnnotation(DBBean.DBTable.class);
|
||||
if (tableAnn != null) {
|
||||
config.tableName = tableAnn.value();
|
||||
config.idColumnName = tableAnn.idColumn();
|
||||
} else {
|
||||
config.tableName = c.getSimpleName();
|
||||
config.tableName = clazz.getSimpleName();
|
||||
config.idColumnName = "id";
|
||||
}
|
||||
|
||||
// Get fields
|
||||
|
||||
List<Field> fields;
|
||||
if (tableAnn != null && tableAnn.superBean())
|
||||
fields = ClassUtil.getAllDeclaredFields(clazz, DBBean.class);
|
||||
else
|
||||
fields = Arrays.asList(clazz.getDeclaredFields());
|
||||
|
||||
// Add the fields in the bean and all the super classes fields
|
||||
for (Class<?> cc = c; cc != DBBean.class; cc = cc.getSuperclass()) {
|
||||
Field[] fields = cc.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
int mod = field.getModifiers();
|
||||
if (!Modifier.isTransient(mod) &&
|
||||
|
|
@ -94,11 +102,8 @@ class DBBeanConfig{
|
|||
config.fields.add(new DBBeanFieldConfig(field));
|
||||
}
|
||||
}
|
||||
if (tableAnn == null || !tableAnn.superBean())
|
||||
break;
|
||||
}
|
||||
|
||||
beanConfigs.put(c.getName(), config);
|
||||
beanConfigs.put(clazz.getName(), config);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
package zutil.parser;
|
||||
|
||||
import zutil.ClassUtil;
|
||||
import zutil.io.file.FileUtil;
|
||||
import zutil.log.LogUtil;
|
||||
import zutil.struct.MutableInt;
|
||||
|
|
@ -412,7 +413,7 @@ public class Templator {
|
|||
else {
|
||||
// Using a loop as the direct lookup throws a exception if no field was found
|
||||
// So this is probably a bit faster
|
||||
for (Field field : obj.getClass().getDeclaredFields()) { // Only look for public fields
|
||||
for (Field field : ClassUtil.getAllDeclaredFields(obj.getClass())) { // Only look for public fields
|
||||
if (field.getName().equals(attrib)) {
|
||||
field.setAccessible(true);
|
||||
return field.get(obj);
|
||||
|
|
|
|||
|
|
@ -209,21 +209,23 @@ public class JSONObjectInputStream extends InputStream implements ObjectInput, C
|
|||
if (json.getString("@object_id") != null && objectCache.containsKey(json.getInt(MD_OBJECT_ID)))
|
||||
return objectCache.get(json.getInt(MD_OBJECT_ID));
|
||||
|
||||
// ------------------------------------------------
|
||||
// Resolve the class
|
||||
Object obj;
|
||||
// Try using explicit class
|
||||
// ------------------------------------------------
|
||||
|
||||
Class<?> objClass;
|
||||
|
||||
// Try using explicit class from target
|
||||
if (type != null) {
|
||||
obj = type.getDeclaredConstructor().newInstance();
|
||||
objClass = type;
|
||||
}
|
||||
// Try using metadata
|
||||
// Try using JSON metadata
|
||||
else if (json.getString(MD_CLASS) != null) {
|
||||
Class<?> objClass = Class.forName(json.getString(MD_CLASS));
|
||||
obj = objClass.getDeclaredConstructor().newInstance();
|
||||
objClass = Class.forName(json.getString(MD_CLASS));
|
||||
}
|
||||
// Search for registered classes
|
||||
else if (registeredClasses.containsKey(key)) {
|
||||
Class<?> objClass = registeredClasses.get(key);
|
||||
obj = objClass.getDeclaredConstructor().newInstance();
|
||||
objClass = registeredClasses.get(key);
|
||||
}
|
||||
// Unknown class
|
||||
else {
|
||||
|
|
@ -231,8 +233,26 @@ public class JSONObjectInputStream extends InputStream implements ObjectInput, C
|
|||
return null;
|
||||
}
|
||||
|
||||
// ------------------------------------------------
|
||||
// Instantiate object
|
||||
// ------------------------------------------------
|
||||
|
||||
Object obj = null;
|
||||
|
||||
// Date and time objects
|
||||
if (Date.class.isAssignableFrom(objClass)) {
|
||||
obj = new Date(json.getLong("timestamp"));
|
||||
}
|
||||
else if (Calendar.class.isAssignableFrom(objClass)) {
|
||||
obj = Calendar.getInstance();
|
||||
((Calendar) obj).setTimeInMillis(json.getLong("timestamp"));
|
||||
}
|
||||
// Instantiate generic object
|
||||
else{
|
||||
obj = objClass.getDeclaredConstructor().newInstance();
|
||||
|
||||
// Read all fields from the new object instance
|
||||
for (Field field : obj.getClass().getDeclaredFields()) {
|
||||
for (Field field : ClassUtil.getAllDeclaredFields(obj.getClass())) {
|
||||
if ((field.getModifiers() & Modifier.STATIC) == 0 &&
|
||||
(field.getModifiers() & Modifier.TRANSIENT) == 0 &&
|
||||
json.get(field.getName()) != null) {
|
||||
|
|
@ -246,6 +266,7 @@ public class JSONObjectInputStream extends InputStream implements ObjectInput, C
|
|||
json.get(field.getName())));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add object to the cache
|
||||
if (json.getString(MD_OBJECT_ID) != null)
|
||||
objectCache.put(json.getInt(MD_OBJECT_ID), obj);
|
||||
|
|
|
|||
|
|
@ -34,13 +34,12 @@ import java.io.*;
|
|||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
import static zutil.parser.json.JSONObjectInputStream.MD_CLASS;
|
||||
import static zutil.parser.json.JSONObjectInputStream.MD_OBJECT_ID;
|
||||
|
||||
|
||||
public class JSONObjectOutputStream extends OutputStream implements ObjectOutput, Closeable{
|
||||
/** If the generated JSON should contain class def meta-data **/
|
||||
private boolean generateMetaData = true;
|
||||
|
|
@ -153,8 +152,16 @@ public class JSONObjectOutputStream extends OutputStream implements ObjectOutput
|
|||
}
|
||||
root.set(MD_CLASS, obj.getClass().getName());
|
||||
}
|
||||
// Add all the fields to the DataNode
|
||||
for (Field field : obj.getClass().getDeclaredFields()) {
|
||||
|
||||
// Date and time objects
|
||||
if (Date.class.isAssignableFrom(objClass)) {
|
||||
root.set("timestamp", ((Date) obj).getTime());
|
||||
}
|
||||
else if (Calendar.class.isAssignableFrom(objClass)) {
|
||||
root.set("timestamp", ((Calendar) obj).getTimeInMillis());
|
||||
}
|
||||
else { // Generic class, Add all the fields to the DataNode
|
||||
for (Field field : ClassUtil.getAllDeclaredFields(obj.getClass())) {
|
||||
if (!Modifier.isStatic(field.getModifiers()) &&
|
||||
!Modifier.isTransient(field.getModifiers())) {
|
||||
field.setAccessible(true);
|
||||
|
|
@ -168,6 +175,7 @@ public class JSONObjectOutputStream extends OutputStream implements ObjectOutput
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
|
|
|
|||
57
test/zutil/ClassUtilTest.java
Normal file
57
test/zutil/ClassUtilTest.java
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package zutil;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class ClassUtilTest extends TestCase {
|
||||
|
||||
public void testGetAllDeclaredFields() {
|
||||
List<Field> fields = ClassUtil.getAllDeclaredFields(TestClass.class);
|
||||
List<String> fieldNames = getFieldNames(fields);
|
||||
|
||||
assertEquals(4, fields.size());
|
||||
assertTrue(fieldNames.contains("superPrivateInt"));
|
||||
assertTrue(fieldNames.contains("superPublicInt"));
|
||||
assertTrue(fieldNames.contains("protectedInt"));
|
||||
assertTrue(fieldNames.contains("publicInt"));
|
||||
|
||||
fields = ClassUtil.getAllDeclaredFields(TestClass.class, TestSuperClass.class);
|
||||
fieldNames = getFieldNames(fields);
|
||||
|
||||
assertEquals(2, fields.size());
|
||||
assertFalse(fieldNames.contains("superPrivateInt"));
|
||||
assertFalse(fieldNames.contains("superPublicInt"));
|
||||
assertTrue(fieldNames.contains("protectedInt"));
|
||||
assertTrue(fieldNames.contains("publicInt"));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------
|
||||
// Utilities
|
||||
// ----------------------------------------------------
|
||||
|
||||
private List<String> getFieldNames(List<Field> fields) {
|
||||
List<String> names = new ArrayList<>();
|
||||
|
||||
for (Field field : fields)
|
||||
names.add(field.getName());
|
||||
return names;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------
|
||||
// Test Classes
|
||||
// ----------------------------------------------------
|
||||
|
||||
public static class TestSuperClass {
|
||||
private int superPrivateInt = 10;
|
||||
public int superPublicInt = 11;
|
||||
}
|
||||
|
||||
public static class TestClass extends TestSuperClass {
|
||||
protected int protectedInt = 20;
|
||||
public int publicInt = 21;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue