Recursively print an objects details - java

How do I print the content of an object recursively?

You can print it recursively by overriding toString in all your classes.
If you want to have a method like printObjectRecursively(Object o) you need to dive into reflection, fetch the fields, print their name and content recursively using printObjectRecursively(someField).
Example:
public class Test {
public static void main(String[] args) {
A a = new A();
System.out.println(a);
}
}
class A {
int i = 5;
B obj = new B();
String str = "hello";
public String toString() {
return String.format("A: [i: %d, obj: %s, str: %s]", i, obj, str);
}
}
class B {
int j = 17;
public String toString() {
return String.format("B: [j: %d]", j);
}
}
Prints:
A: [i: 5, obj: B: [j: 17], str: hello]
A reflection-based recursive print method could be written something like this
private static final List LEAVES = Arrays.asList(
Boolean.class, Character.class, Byte.class, Short.class,
Integer.class, Long.class, Float.class, Double.class, Void.class,
String.class);
public static String toStringRecursive(Object o) throws Exception {
if (o == null)
return "null";
if (LEAVES.contains(o.getClass()))
return o.toString();
StringBuilder sb = new StringBuilder();
sb.append(o.getClass().getSimpleName()).append(": [");
for (Field f : o.getClass().getDeclaredFields()) {
if (Modifier.isStatic(f.getModifiers()))
continue;
f.setAccessible(true);
sb.append(f.getName()).append(": ");
sb.append(toStringRecursive(f.get(o))).append(" ");
}
sb.append("]");
return sb.toString();
}

You can use:
ToStringBuilder.reflectionToString(this);
Apache Common Lang contains ToStringBuilder class. You can define different style with ToStringStyle object.

I've had great success doing this on a casual basis using XStream to dump JSON representations of objects. It recurses down objects and just seems to do what you want it to do most of the time. And it's super lightweight. Example:
private static final XStream jsonXStream =
new XStream(new JsonHierarchicalStreamDriver());
public static String toDebugString(Object object) {
return jsonXStream.toXML(object);
// ignore "toXML" name, it's going to be JSON.
}

You should implement the toString method for your classes - it will print the information about the class members - usually using their toString methods. |Then you jut iterate through the collection and call toString of each item

Do you really need print this informations out? Maybe watch during debbuging will be enough?

You are looking for something similar to PHP's var_dump, see if this question is of any help: What is the Java equivalent of PHP var_dump?
Also, have a look at reflection: http://java.sun.com/developer/technicalArticles/ALT/Reflection/

You can override the toString method.
Example:
class foo
{
int i,j;
String toString()
{
StringBuilder b=new StringBuilder();
return b.append(i).append(j).toString();
}
}

Use one of the serialization libraries like Jackson (JSON).
This dumps everything in plain text. If you use a Javascript capable editor to prettify the content, with a bit of luck, you might actually make some sense out of it.
If a lot of the objects are not serializable, you might end up with a lot of readable gibberish which will not help anything, unfortunately,
YMMV

In some cases it is easy to use Gson to print object. But sometimes gson does not work.
Here I just improve aioobe' answer for this case:
don't print printed objects (protect from infinite cycles)
print collections
don't go deeply on few basic types, like BigInteger
private static final Set<Object> looked = new HashSet<>();
private static final List LEAVES = Arrays.asList(
Boolean.class, Character.class, Byte.class, Short.class,
Integer.class, Long.class, Float.class, Double.class, Void.class,
String.class, java.math.BigInteger.class, java.math.BigDecimal.class);
public static void toStringRecursive(Object o, StringBuilder sb) throws Exception {
if (o == null) {
sb.append("null");
return;
}
if (looked.contains(o)) return;
looked.add(o);
if (LEAVES.contains(o.getClass())) {
sb.append(o);
return;
}
sb.append(o.getClass().getSimpleName()).append(": [");
if (o.getClass().isArray()) {
for (Object x : (Object[]) o) {
toStringRecursive(x, sb);
}
} else if (Iterable.class.isAssignableFrom(o.getClass())) {
for (Object x : (Iterable) o) {
toStringRecursive(x, sb);
}
} else if (Map.class.isAssignableFrom(o.getClass())) {
for (Object entry : ((Map)o).entrySet()) {
toStringRecursive(entry, sb);
}
} else {
for (Field f : o.getClass().getDeclaredFields()) {
if (Modifier.isStatic(f.getModifiers()))
continue;
f.setAccessible(true);
sb.append(f.getName()).append(": ");
toStringRecursive(f.get(o), sb);
sb.append(" ");
}
}
sb.append("]\n");
}

Related

java.lang.ClassCastException: [Z cannot be cast to [Ljava.lang.String in reflective toString on model class

I have a model class in java and I overwrote the toString to provide me with a custom toString. The toString uses reflection to find the field names and values and it works when I run it locally via my ide. However when I run it via mvn agents I always seem to get the error:
java.lang.ClassCastException: [Z cannot be cast to [Ljava.lang.String
Here is the toString:
#SneakyThrows
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
Class<?> thisClass = Class.forName(this.getClass().getName());
Field[] aClassFields = thisClass.getDeclaredFields();
for (Field f : aClassFields) {
String fName = f.getName();
fName = fName.startsWith("_") ? fName.substring(1) : fName;
if (null != f.get(this)) {
if (f.get(this) instanceof String || f.get(this) instanceof List) {
sb.append(getVariableNameStr(fName, f.get(this).toString()));
} else {
StringBuilder stringArrayStr = new StringBuilder();
for (String s : (String[]) f.get(this)) {
stringArrayStr.append(fName).append(": ").append(s).append(", ");
}
sb.append(stringArrayStr);
}
}
}
return sb.toString().substring(0, sb.toString().length() - 2);
}
The line it fails on in the code is the following:
for (String s : (String[]) f.get(this)) {
Why does this pass locally and fail using mvn?
Can anybody tell me what is incorrect about this line?
Just to clear up - the model class has 3 types of field - String, List and String array. The errored line occurs on String array entries.
A
I would assume its caused by some other libraries or test suite touching your code. Or some difference in configuration between local run and maven might cause your objects to be wrapped in some other proxy classes, as proxy classes are often used by frameworks like spring.
You should filter out fields that are not part of object, by removing static and synthetic fields. As like I said in comment, [Z is a boolean[] field, so for sure you are getting some extra fields here.
Also reflections are already bad for performance, and you are repeating field.get call multiple times for no reason. And I don't understand at all why you are assuming field to be of String[] type without checking it.
public String toString() {
StringBuilder sb = new StringBuilder();
Class<?> thisClass = this.getClass();
Field[] aClassFields = thisClass.getDeclaredFields();
for (Field f : aClassFields) {
//skip static and synthetic fields:
if (f.isSynthetic() || Modifier.isStatic(f.getModifiers())) continue;
// get value only once:
Object value = f.get(this);
String fName = f.getName();
fName = fName.startsWith("_") ? fName.substring(1) : fName;
if (value != null) { // and use this value here
if (value instanceOf String[]) {
StringBuilder stringArrayStr = new StringBuilder();
for (String s : (String[]) value) { // and here
stringArrayStr.append(fName).append(": ").append(s).append(", ");
}
sb.append(stringArrayStr);
} else {
sb.append(getVariableNameStr(fName, value.toString()));
}
}
}
return sb.toString().substring(0, sb.toString().length() - 2);
}
I also reordered ifs to handle String[] case first, and use the simple generic toString for rest of possible objects, as this seems to be your case.
Also it would be much better solution to just generate normal toString method or use some libraries like ToStringBuilder from apache commons. As it does not look like you need to use reflections here at all.
[Z means boolean[] - not String[]. So the field is of type boolean[].

Java generics and numeric types

I'd like to create a generic method which does effectively this:
class MyClass {
static <T extends Number> T sloppyParseNumber(String str) {
try {
return T.valueOf(str);
} catch (Exception e) {
return (T)0;
}
}
}
Now above does not compile for two reasons: there's no Number.valueOf() method and 0 can't be cast to T.
Example usage:
String value = "0.00000001";
System.out.println("Double: " + MyClass.<Double>sloppyParseNumber(value));
System.out.println("Float: " + MyClass.<Float>sloppyParseNumber(value));
double d = MyClass.sloppyParseNumber(value);
float f = MyClass.sloppyParseNumber(value);
Is implementing above generic method possible with Java? If yes, how? If no, what's a good alternative approach?
Edit: there seems to be a few possible duplicates, but I did not find one, which covers exactly this. I'm hoping there's some trick to pull, which would allow these two operations: parse string to a Number subclass, and return 0 value for a Number subclass.
I agree 100% with TofuBeer. But in case you wish to avoid verbosity for time sake, this should also do:
static <T extends Number> T sloppyParseNumber(String str,Class<T> clas) {
if (clas == null) throw new NullPointerException("clas is null");
try {
if(clas.equals(Integer.class)) {
return (T) Integer.valueOf(str);
}
else if(clas.equals(Double.class)) {
return (T) Double.valueOf(str);
}
//so on
catch(NumberFormatException|NullPointerException ex) {
// force call with valid arguments
return sloppyParseNumber("0", clas);
}
throw new IllegalArgumentException("Invalid clas " + clas);
}
But purely from T, you cannot get the type at runtime.
Java generics only provide compile time checks and the type information is pretty much thrown away after compilation. So the statement T.valueOf isn't possible in Java. The solution is to go the verbose way as already mentioned in the comments. Also, is there any reason why you want to do MyClass.<Double>sloppyParseNumber(value) but not MyClass.sloppyParseDouble(value) since you are anyway specifying the type at compile time?
Static methods are bound by the type, since the type is, at best, Number and Number doesn't have a valueOf method what you are after isn't going to work.
The easiest way is to just make a number of static methods like sloppyParseInt, sloppyParseFloat, etc...
You could do something like this, not sure I like it, and can probably be improved on:
public class Main
{
private static final Map<Class<? extends Number>, NumberConverter> CONVERTERS;
static
{
CONVERTERS = new HashMap<>();
CONVERTERS.put(Integer.class, new IntegerConverter());
}
public static void main(String[] args)
{
Number valueA;
Number valueB;
valueA = CONVERTERS.get(Integer.class).convert("42");
valueB = CONVERTERS.get(Integer.class).convert("Hello, World!");
System.out.println(valueA);
System.out.println(valueB);
}
}
interface NumberConverter<T extends Number>
{
T convert(String str);
}
class IntegerConverter
implements NumberConverter<Integer>
{
#Override
public Integer convert(String str)
{
try
{
return Integer.valueOf(str);
}
catch (NumberFormatException ex)
{
return 0;
}
}
}
So, I decided on an alternative approach:
static String trimTo0(String str) {
if (str == null) return "0";
str = str.trim();
if (str.isEmpty()) return "0";
return str;
}
Usage:
String value = null;
System.out println("Double value: " + Double.parseDouble(trimTo0(value)));
Note that this is more limited than the method in the question, this does not convert invalid, non-numeric strings to "0". Doing that fully would require two separate methods, one supporting decimal point and another just supporting integers.
You can try this:
private <T> T convertToType(Class<T> clazz,String str) throws Exception {
return clazz.getConstructor(String.class).newInstance(str);
}
Here you need to consider that the Type must have a constructor with a String parameter.

Using primitive types with ClassLoader

I've got a piece of code that is used to turn string representations delivered by Class.getCanonicalName() into their corresponding instances of Class. This usually can be done using ClassLoader.loadClass("className"). However, it fails on primitive types throwing a ClassNotFoundException. The only solution I came across was something like this:
private Class<?> stringToClass(String className) throws ClassNotFoundException {
if("int".equals(className)) {
return int.class;
} else if("short".equals(className)) {
return short.class;
} else if("long".equals(className)) {
return long.class;
} else if("float".equals(className)) {
return float.class;
} else if("double".equals(className)) {
return double.class;
} else if("boolean".equals(className)) {
return boolean.class;
}
return ClassLoader.getSystemClassLoader().loadClass(className);
}
That seems very nasty to me, so is there any clean approach for this?
Since you have an exception for this: Class.forName(int.class.getName()), I would say this is the way to go.
Checking Spring framework code http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/util/ClassUtils.html class, method resolvePrimitiveClassName , you will see that they do the same thing, but with a map ;). Source code: http://grepcode.com/file/repository.springsource.com/org.springframework/org.springframework.core/3.1.0/org/springframework/util/ClassUtils.java#ClassUtils.resolvePrimitiveClassName%28java.lang.String%29
Something like this:
private static final Map primitiveTypeNameMap = new HashMap(16);
// and populate like this
primitiveTypeNames.addAll(Arrays.asList(new Class[] {
boolean[].class, byte[].class, char[].class, double[].class,
float[].class, int[].class, long[].class, short[].class}));
for (Iterator it = primitiveTypeNames.iterator(); it.hasNext();) {
Class primitiveClass = (Class) it.next();
primitiveTypeNameMap.put(primitiveClass.getName(), primitiveClass);
}
Just to make life more fun, you'll also have trouble with arrays. This gets around the array problem:
private Pattern arrayPattern = Pattern.compile("([\\w\\.]*)\\[\\]");
public Class<?> getClassFor(String className) throws ClassNotFoundException {
Matcher m = arrayPattern.matcher(className);
if(m.find()) {
String elementName = m.group(1);
return Class.forName("[L" + elementName + ";"); // see below
}
return Class.forName(className);
}
The wrapping of the class name in [L(classname); - that I sourced here. I can't see a cleaner way of doing it, but I'm sure there must be one.
Of course an array of primitive types will need a further set of special-case logic...

Invoking a same method just once in java

I have four different classes classA, classB, classC and classD. All the four classes have the same static method search() which takes two string parameters. If i want to invoke static method search in four different classes from main class at once. How can I do that. For now my code is as follows for main class. I need to execute the same thing for other 3 classes also. How can i do that and display the results of other 3 in the same way as for classA. The way search is done in 4 classes r different but they should give the same result.
Main() {
Object[] zy;
for (String pattern : Read.arrayList) {
List<Integer> results = ClassA.findAll(pattern, dataToSearch);
zy = results.toArray();
for (int i = 0; i < zy.length; i++) {
System.out.println(" Pattern searched " + pattern + " match is found at index : "+ results);
}
}
if (zy.length == 0) {
System.out.println("Nothing matched");
}
}
I strongly recommend you change this to non-static methods. Look how easy and nice is when you will seperate an interface:
public interface Common {
List<Integer> findAll(String pattern, String dataToSearch);
}
public class A implements Common ...
public class B implements Common ...
public class C implements Common ...
public class D implements Common ...
// in main:
List<Common> allYourClasses = new ArrayList<Common>();
allYourClasses.add(new A());
allYourClasses.add(new B());
allYourClasses.add(new C());
allYourClasses.add(new D());
List<Integer> result = new ArrayList<Integer>();
for (Common c : allYourClasses) {
result.addAll(c.findAll(pattern, dataToSearch));
}
1 - You should NOT do this. Avoid static methods. One of the reason being they can not be called without the exact class. A group of classes that implement a simple interfaces will work faster, safer and better in every way
2 - You can (but you shouldn't) do something like this:
for (Class<?> clazz : new Class[] { ClassA.class, ClassB.class,
ClassC.class }) {
Object[] zy = null;
String dataToSearch = "";
String[] arrayList = { "a" };
for (String pattern : arrayList) {
List<Integer> results = findAllForClass(clazz, pattern,
dataToSearch);
zy = results.toArray();
for (int i = 0; i < zy.length; i++) {
System.out.println(" Pattern searched " + pattern
+ " match is found at index : " + results);
}
}
if (zy.length == 0) {
System.out.println("Nothing matched");
}
}
#SuppressWarnings("unchecked")
public static List<Integer> findAllForClass(Class<?> clazz, String pattern,
String dataToSearch) {
List<Integer> list = null;
try {
list = (List<Integer>) clazz.getDeclaredMethod("findAll", String.class,
String.class).invoke(null, pattern, dataToSearch);
} catch (Exception e) {
list = Collections.emptyList();
}
return list;
}
You see the #supresswarning and the try/catch? well, this is a hint: is telling you you this code is at least suspicious. It is in fact unsafe, non well performant, and is a stupid workaround.
(But we all did something like that once in our lives)
I can't really figure out why would anyone do that.
That said, you could have a method taking a Class as a parameter and calling the method explicitly by name (getMethod.../invoke()).
That puts you back in non static world and you can iterate over the classes you want to invoke. (But again, why use statics in the first place?)
Pseudo untested code:
public void invokeStatic(Class clazz, String method, Class<?> paramsTypes[], Object[] params) {
Method method = clazz.getMethod(method, paramsType);
method.invoke(params);
}
If you want to group all of the results together, just keep adding results to your list:
List<Integer> results = ClassA.findAll(pattern, dataToSearch);
results.addAll(ClassB.findAll(pattern, dataToSearch));
// etc.

Recursive function for getters/setters?

I am looking for an algorithm in Java that creates an object thats attributes are set to the first not-null value of a string of objects. Consider this array (I will use JSON syntax to represent the array for the sake of simplicity):
{
"objects": [
{
"id": 1,
"val1": null,
"val2": null,
"val3": 2.0
},
{
"id": 2,
"val1": null,
"val2": 3.8,
"val3": 6.0
},
{
"id": 3,
"val1": 1.98,
"val2": 1.8,
"val3": 9.0
}
]
}
In the end, I want one object that looks like this:
{
"id": 1,
"val1": 1.98,
"val2": 3.8,
"val3": 2.0
}
Where val1 comes from the third object, val2 from the secound and val3 and id from the first, because these are the first objects found where the attribute isn't null.
What I have done so far in Java and what works really fine is this:
// Java code that proceeds a deserialized representation of the
// above mentioned array
int k = 0;
while (bs.getVal1() == null) {
k++;
bs.setVal1(objectArray.get(k).getVal1());
}
However, I am not satisfied, because I would have to write this code four times (getId, getVal1, getVal2, getVal3). I am sure there must be a rather generic approach. Any Java guru who could give a Java beginner an advice?
Before getting to your actual question, here's a better way of writing your existing loop: (replace Object with whatever the actual type is)
for (Object o : objectArray) {
Double d = o.getVal1();
if (d != null) {
bs.setVal1(d);
break;
}
}
Considering the way your objects are laid out now, there isn't a better way to do it. But you can do better if you change the structure of your objects.
One way is to put your different value fields (val1, val2, ...) into an array:
Double val[] = new Double[3]; // for 3 val fields
public Double getVal(int index) {
return val[index];
}
public void setVal(int index, Double value) {
val[index] = value;
}
Then you can simply access the fields by their index and set all fields of bs in one iteration of the object array:
for (Object o : objectArray) {
for (int i = 0; i < 3; i++) {
Double d = o.getVal(i);
if (d != null) {
bs.setVal(i, d);
break;
}
}
}
+1 - Code repetition is a problem that can sometimes be hard to overcome in Java.
One solution is to create an Iterable class which allows you to iterate over the values in one of those objects as if they were in an array. This takes away some of the repetition from your code without sacraficing the legibility benefits of named variables.
Note that In my code below, I've created a separate iterable class, but you could also simply make the POD class iterable (which one of these is the best option for you depends on details you didn't cover with your example code):
(warning - not tested yet)
import java.util.Iterator;
public class Main {
static class POD{
Integer id; Double val1; Double val2; Double val3;
public POD(Integer i, Double v1, Double v2, Double v3){
id=i; val1=v1; val2=v2; val3=v3;
}
public POD(){ }
}
static class PODFields implements Iterable<Number>{
private POD pod;
public PODFields(POD pod){
this.pod=pod;
}
public PODFieldsIterator iterator() {
return new PODFieldsIterator(pod);
}
}
static class PODFieldsIterator implements Iterator<Number>{
int cur=0;
POD pod;
public PODFieldsIterator(POD pod) {
this.pod=pod;
}
public boolean hasNext() { return cur<4; }
public Number next() {
switch(cur++){
case 0:
return pod.id;
case 1:
return pod.val1;
case 2:
return pod.val2;
case 3:
return pod.val3;
}
return null;//(there are better ways to handle this case, but whatever)
}
public void remove() { throw new UnsupportedOperationException("You cannot remove a POD field."); }
}
public static void main(String[] args) {
POD [] objectArray = {new POD(1,null,null,2.0),
new POD(1,null,null,2.0),
new POD(1,null,null,2.0),
new POD(1,null,null,2.0)};
POD finalObject=new POD();
for (POD cur : objectArray){
PODFieldsIterator curFields = new PODFields(cur).iterator();
for (Number finalValue : new PODFields(finalObject)){
Number curValue = curFields.next();
if (finalValue==null)
finalValue=curValue;
}
}
for (Number finalValue : new PODFields(finalObject))
System.out.println(finalValue);
}
}
Edit: Oops - looks like I forgot Numbers are immutable. I suppose you could overcome this by having the iterator return functors or something, but that's possibly going a bit overboard.
Whenever you want to eliminate code duplication, one of the first things you look for is whether you can extract a reusable method. Reflection helps you call arbitrary methods in a reusable way. Its not the prettiest thing in the world, but this method works for you:
#SuppressWarnings("unchecked")
public <T> T firstNonNull(String methodName, TestObject... objs) {
try {
Method m = TestObject.class.getMethod(methodName, (Class[])null);
for (TestObject testObj : objs) {
T retVal = (T)m.invoke(testObj, (Object[])null);
if (retVal != null) return retVal;
}
return null;
} catch (Exception e) {
//log, at a minimum
return null;
}
}
Testing with a class like this:
public class TestObject {
Integer id;
String val1;
Map<String, Boolean> val2;
public int getId() {
return id;
}
public String getVal1() {
return val1;
}
public Map<String, Boolean> getVal2() {
return val2;
}
}
This JUnit test demonstrates its usage:
#org.junit.Test
public void testFirstNonNull() {
TestObject t1 = new TestObject();
t1.id = 1;
t1.val1 = "Hello";
t1.val2 = null;
TestObject t2 = new TestObject();
Map<String, Boolean> map = new HashMap<String, Boolean>();
t2.id = null;
t2.val1 = "World";
t2.val2 = map;
TestObject result = new TestObject();
result.id = firstNonNull("getId", t1, t2);
result.val1 = firstNonNull("getVal1", t1, t2);
result.val2 = firstNonNull("getVal2", t1, t2);
Assert.assertEquals(result.id, (Integer)1);
Assert.assertEquals(result.val1, "Hello");
Assert.assertSame(result.val2, map);
}

Categories