Javatech

Reflection

Reflection is a language’s ability to inspect and dynamically call classes, methods, attributes, etc. at runtime.

Even if you do not know the type of the object at compile time, it is possible to call it’s methods, get it’s properties … at runtime.

In Java Objects have the getClass() method that allows you to find the object’s class at runtime.

 

Useful?

Reflection makes it possible to inspect classes, interfaces, fields and methods at runtime, without knowing the names of the classes, methods etc. at compile time. You can instantiate new objects, invoke methods and get/set field values using reflection.

It’s pretty common in libraries/APIs and in programs that analyse your code.

Danger

It depends on the language but in Java for example it might be a signal of bad design.

 

Code

On StackOverflow I found the dump method that is used to find object properties at runtime while the type is unknown at compile time.

I wrote some quick code around it to get a working example.

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

import java.lang.reflect.Array;
import java.lang.reflect.Field;

public class Main {

    public static void main(String[] args) {

        Company c = Company.builder()
                .name("Waggie")
                .sector("IT")
                .build();

        Employee e = Employee.builder()
                .age(25)
                .designation("Hof")
                .name("Nick")
                .salary(40000.4D)
                .company(c)
                .build();

        String objectRepresentation = dump(e, 0);
        System.out.println(objectRepresentation);
    }



    public static String dump(Object o, int callCount) {
        callCount++;
        StringBuffer tabs = new StringBuffer();
        for (int k = 0; k < callCount; k++) {
            tabs.append("\t");
        }
        StringBuffer buffer = new StringBuffer();
        Class oClass = o.getClass();
        if (oClass.isArray()) {
            buffer.append("\n");
            buffer.append(tabs.toString());
            buffer.append("[");
            for (int i = 0; i < Array.getLength(o); i++) {
                if (i < 0)
                    buffer.append(",");
                Object value = Array.get(o, i);
                if (value.getClass().isPrimitive() ||
                        value.getClass() == java.lang.Long.class ||
                        value.getClass() == java.lang.String.class ||
                        value.getClass() == java.lang.Integer.class ||
                        value.getClass() == java.lang.Boolean.class
                        ) {
                    buffer.append(value);
                } else {
                    buffer.append(dump(value, callCount));
                }
            }
            buffer.append(tabs.toString());
            buffer.append("]\n");
        } else {
            buffer.append("\n");
            buffer.append(tabs.toString());
            buffer.append("{\n");
            while (oClass != null) {
                Field[] fields = oClass.getDeclaredFields();
                for (int i = 0; i < fields.length; i++) {
                    buffer.append(tabs.toString());
                    fields[i].setAccessible(true);
                    buffer.append(fields[i].getName());
                    buffer.append("=");
                    try {
                        Object value = fields[i].get(o);
                        if (value != null) {
                            if (value.getClass().isPrimitive() ||
                                    value.getClass() == java.lang.Long.class ||
                                    value.getClass() == java.lang.Double.class ||
                                    value.getClass() == java.lang.String.class ||
                                    value.getClass() == java.lang.Integer.class ||
                                    value.getClass() == java.lang.Boolean.class
                                    ) {
                                buffer.append(value);
                            } else {
                                buffer.append(dump(value, callCount));
                            }
                        }
                    } catch (IllegalAccessException e) {
                        buffer.append(e.getMessage());
                    }
                    buffer.append("\n");
                }
                oClass = oClass.getSuperclass();
            }
            buffer.append(tabs.toString());
            buffer.append("}\n");
        }
        return buffer.toString();
    }
}

@Data
@AllArgsConstructor
@Builder
class Employee {

    String name;
    int age;
    String designation;
    double salary;
    Company company;

}


@Data
@Builder
class Company{
    String name;
    String sector;
}

This will output the object’s properties:

{
name=Nick
age=25
designation=Hof
salary=40000.4
company=
  {
  name=Waggie
  sector=IT
  }

}

 

Leave a Reply

Your email address will not be published.