loading...
Cover image for What is Java reflection and how to use?

What is Java reflection and how to use?

eddiescj profile image EddieSCJ ・6 min read

Table of Contents - English

A New Way to Post

Let's start our weekly post. After a long time distant I am coming back to write for you and help everyone that needs help with Java or another language that I know.

Here are my contacts:

  1. Gmail: EddieProfessionalMail@gmail.com
  2. Instagram: CoderEddie

Going back to our main subject... I decided to write these articles in English and Portuguese to make it more accessible.
So, how it will work?

I would like to advise that I have A LOT of new things to tell, like Spring Boot, Coding Guidelines, and some curiosities about Java.

Let's go!!!!

Finally, what is Java Reflection !???

In programming, reflection is the ability to change, process, or introspect its structure.
But, how as??

Just imagine you have a class that you want to catalog all your methods in a text file, or better, imagine you have some rules in your application and you want to insert them in your database without insert 100 rules manually.

To do it you will write a routine to search all the rules and verify if they are in the database and if they aren't you will simply insert it.

You can use Java Reflection to search.

Here it's the official documentation: Java Reflections

So, go to examples!!!

A Challenger Example

Now we will build a JSON dynamically using the class and your values using only java reflections and the GSON library.

To start, we will create two classes, car and passenger.

I am using:

We will use Gradle to download the dependencies easily. Then, start your Gradle project, please.

If you are using the IDEA, maybe you will need to create a main class in the project.

public class Main {

    public static void Main(String args[]){

    }

}

Now let's create the Car and Passenger classes.

Here are they:

public class Passenger {

    private String name;
    private Integer age;

    public Passenger(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

And...

import java.util.List;

public class Car {

    private String name;
    private Double maxVelocity;
    private Integer maxPassengers;
    private List<Passenger> passengers;

    public Car(String name, Double maxVelocity, Integer maxPassengers, List<Passenger> passengers) {
        this.name = name;
        this.maxVelocity = maxVelocity;
        this.maxPassengers = maxPassengers;
        this.passengers = passengers;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getMaxVelocity() {
        return maxVelocity;
    }

    public void setMaxVelocity(double maxVelocity) {
        this.maxVelocity = maxVelocity;
    }

    public int getMaxPassengers() {
        return maxPassengers;
    }

    public void setMaxPassengers(int maxPassengers) {
        this.maxPassengers = maxPassengers;
    }

    public List<Passenger> getPassengers() {
        return passengers;
    }

    public void setPassengers(List<Passenger> passengers) {
        this.passengers = passengers;
    }

}

To build a complete example we will use a relationship between car and passengers. Let's code.

To start I create some mock data to use in our code:

    Passenger bob = new Passenger("Bob", 12);
    Passenger Jhon = new Passenger("Jhon", 12);
    Passenger maria = new Passenger("Maria", 12);
    Passenger alice = new Passenger("Alice", 12);
    Passenger sam = new Passenger("Samantha", 12);
    Passenger marcus = new Passenger("Marcus", 12);
    Passenger mark = new Passenger("Mark", 12);

    Car ferrarM12 = new Car("M12 AX", 324.00, 2, Arrays.asList(bob, sam));
    Car enterpriseCar = new Car("Some Enterprise Car", 120.00, 6, Arrays.asList(Jhon, maria, alice));
    Car familyCar = new Car("Some Family Car", 120.00, 10, Arrays.asList(bob, Jhon, maria, sam, marcus, alice, mark));

After it, we are ready to build our Util Class.
Our Util Class is answerable to build and return our JSON, alright?

First, there is a model of the complete and final class.

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import org.json.JSONObject;

import java.lang.reflect.Field;
import java.util.Arrays;

public class Util {

    public static String getJson(Object object) throws IllegalAccessException {
        JSONObject jsonObject = new JSONObject();

        Field[] fields = object.getClass().getDeclaredFields();

        for (int i = 0; i < fields.length; i++) {
            fields[i].setAccessible(true);
            jsonObject.put(fields[i].getName(), fields[i].get(object));
        }

        Gson gson = new GsonBuilder().setPrettyPrinting().create();
        JsonParser jsonParser = new JsonParser();
        JsonElement jsonElement = jsonParser.parse(jsonObject.toString());
        String finalJson = gson.toJson(jsonElement);
        return finalJson;
    }

    private static void printFields(Object object) {
        Field[] fields = object.getClass().getDeclaredFields();

        Arrays.stream(fields).forEach(field -> {
            System.out.println(field.getName());
        });
    }

}

And now????
Now we will part it and I will explain everything to you.

The first thing I did was to test the fields.

private static void printFields(Object object) {
        Field[] fields = object.getClass().getDeclaredFields();

        Arrays.stream(fields).forEach(field -> {
            System.out.println(field.getName());
        });
    }

Here I instantiate a primitive array with my possible fields, there are two types to invoke it, with getFields() get all fields, including fields of Object (the mother of everyone, the one above all), another way is to invoke getDeclaredFields().

When you call only declaredFields() you call the fields you created, after, we can iterate the field array that is returned by the called method. If it is working, just go to the next step.

Look:

 public static String getJson(Object object) throws IllegalAccessException {
        JSONObject jsonObject = new JSONObject();
        ...
    }

This JSONObject is a Class of the org.json package we imported at the Gradle archive.
Use: compile group: 'org.json', name: 'json', version: '20200518'

Field[] fields = object.getClass().getDeclaredFields();

        for (int i = 0; i < fields.length; i++) {
            fields[i].setAccessible(true);
            jsonObject.put(fields[i].getName(), fields[i].get(object));
        }

Now we will repeat what we did before printing the field names, first take all the declared fields and iterate it. Second, you have to make the property accessible because originally the property was created as private. Setting it as accessible we can get the value and do anything we want to do.

Recall we create a JSON object to save our data and build it. Now just put the value in the fields and it's finished. But how get the value instantiated in our object instance?????

Has nothing to worry about, the reflect library has a get property returns the variable value using the object instance.

We got the field name and its' value, it was put in our JSON model, our loop will fill it and it is ready!!! Only remain some adjustments to see it running.

Gson gson = new GsonBuilder().setPrettyPrinting().create();
        JsonParser jsonParser = new JsonParser();
        JsonElement jsonElement = 

jsonParser.parse(jsonObject.toString());
        String finalJson = gson.toJson(jsonElement);
        return finalJson;

You didn't see the Gson in use, but here is its' function, we are using it to create a prettyPrinting instance to resolve and format our final JSON.

To create a Java JSON element we have to create a JSON parser and parse our toString() result of our JSONObject to the parser, it will do its' job and return for us a JSON element. Finally, we request the GSON to format our JSON element and return a formatted and readable string.

After, do everything you want to do with it. It is obvious that we don't need to do it in a real programming situation, the spring boot does it for us, but it is a good example to show how to use the reflect package and use java code to create, get and destroy code.

Final Main:

import domain.Car;
import domain.Passenger;

import java.util.Arrays;

public class Main {

    public static void main(String[] args) throws IllegalAccessException {
        Passenger bob = new Passenger("Bob", 12);
        Passenger Jhon = new Passenger("Jhon", 12);
        Passenger maria = new Passenger("Maria", 12);
        Passenger alice = new Passenger("Alice", 12);
        Passenger sam = new Passenger("Samantha", 12);
        Passenger marcus = new Passenger("Marcus", 12);
        Passenger mark = new Passenger("Mark", 12);

        Car ferrariM12 = new Car("M12 AX", 324.00, 2, Arrays.asList(bob, sam));
        Car enterpriseCar = new Car("Some Enterprise Car", 120.00, 6, Arrays.asList(Jhon, maria, alice));
        Car familyCar = new Car("Some Family Car", 120.00, 10, Arrays.asList(bob, Jhon, maria, sam, marcus, alice, mark));

        System.out.println(Util.getJson(ferrariM12));
        System.out.println(Util.getJson(Jhon));
    }
}

For everyone who saw my article, I am very thankful. If you have any suggestions or doubts, just contact me by email, Linkedin, or any other contact way. Here is the GitHub project link Github Project Link.

See you next. If it helped you, liked and share to help other people.

Posted on by:

eddiescj profile

EddieSCJ

@eddiescj

Hello, my name is Edcleidson and I am a FullStack Freelancer Developer (With Java and Flutter), junior researcher in a ECG Project, programming marathons competitor and I love take photos.

Discussion

pic
Editor guide
 

While run-time reflection sometimes might be useful, in general case it should be avoided and replaced with compile-time reflection. Custom annotation processor usually is a most convenient way to implemented it.