Reputation: 13516
I have a number of classes which can include one or more properties of the type TranslatableText
. Also, some classes may have properties which themselves include such properties such as List<TranslatableText>
or Map<String, TranslatableText>
.
How would you go about scanning these classes in an efficient way, also picking up instances of TranslatableText
in generic collections?
class Project{
String id;
TranslatableText name;
List<Action> actions;
}
class Action {
String id;
TranslatableText name;
TranslatableText description;
}
// getter & setters omitted
Upvotes: 2
Views: 3285
Reputation: 13516
Thanks to Peter Lawrey for the initial idea. This is what worked (so far) for me. I had to avoid circular recursion which is why I added the visited
list. Arrays
, Collections
and Maps
are scanned which is good enough for me at the moment.
/**
* Examine class members for TranslatableTexts. Traverse down into
* properties including Collections and Maps but ignoring java.lang classes
*
* @param obj
* @return
*/
public static Collection<? extends TranslatableText> getTranslatables(
Object obj, List<Object> visited)
{
List<TranslatableText> result = new ArrayList<TranslatableText>();
if (obj instanceof TranslatableText)
{
result.add((TranslatableText) obj);
return result;
}
if(visited.contains(obj))
return result;
visited.add(obj);
for (Field f : obj.getClass().getDeclaredFields())
{
f.setAccessible(true);
Class type = f.getType();
if (type.isPrimitive() == false
&& (type.getPackage() == null || type.getPackage()
.getName().startsWith("java.lang") == false))
{
try
{
Object value = f.get(obj);
if (value != null)
{
if (type.isArray())
{
Class arraytype = type.getComponentType();
if (arraytype == TranslatableText.class)
{
TranslatableText[] tt = (TranslatableText[]) value;
if (tt != null)
{
for (TranslatableText t : tt)
{
result.add(t);
}
}
}
}
else if (type == TranslatableText.class)
{
TranslatableText tt = (TranslatableText) value;
if (tt != null)
result.add(tt);
}
else if (value instanceof Collection)
{
for (Object o : (Collection<?>) value)
{
result.addAll(getTranslatables(o, visited));
}
}
else if (value instanceof Map)
{
for (Object o : ((Map) value).values())
{
result.addAll(getTranslatables(o, visited));
}
}
else
{
result.addAll(getTranslatables(value, visited));
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
return result;
}
Upvotes: 0
Reputation: 533492
You can use a loop like this
// for super classes, use recursion.
for(Field f : obj.getClass().getDeclaredFields()) {
Class type = f.getType();
if (type == String.class || type == TranslatableText.class) {
Object value = f.get(object);
if (value != null)
map.put(f.getName(), value.toString());
}
Upvotes: 2