DEV Community

Cover image for Build Mini Framework Using Java Reflection
Madhan Kumar
Madhan Kumar

Posted on

Build Mini Framework Using Java Reflection

Mastering reflection while crafting your own lightweight framwork:

Introduction:

In this article, we are going to see how to create a mini framework using reflection in Java. This is a slightly advanced concept, so before delving into it, you should have a basic understanding of Spring Boot core concepts and annotations. That will help you follow the logic and purpose behind what we’re building.

What’s the purpose of building frameworks like this?
Take Spring Boot as an example, it was created to reduce the heavy configuration that developers had to deal with in the traditional Spring Framework. In the same way, creating our own custom mini frameworks helps us simplify repetitive tasks, reduce boilerplate code, and minimize workload in our applications and make our applications more efficient and developer-friendly.

So in this article, we’re going to build a mini framework (or toolkit) to solve a specific problem. This is just one example, you can use the same approach to create custom frameworks for any kind of problem or improvement in your application where you see repetitive code or unnecessary complexity.

Now, let’s dive into the problem we’re going to solve.

When you are writing unit tests for the larger application, creating test data manually can feel like a chore. You spend time hardcoding dummy names, emails, and numbers again and again for every test. It is repetitive and eats into your productivity.

That’s where our custom mini-framework comes in. This allows you to automatically generate sample data for any Java class just by adding a few annotations. No external libraries, no complicated setup. Just pure Java and reflection doing the magic behind the scenes.

Whether you’re testing APIs, filling tables with fake users, or mocking objects for performance testing, this tool or framework can save you time and reduce boilerplate.

What It Does:

Framework Name: TestDataX

This mini-framework auto-fills your object fields with random or sample data based on field type and annotation.

Perfect for:

  • Unit test setup.
  • Fake data generation for UI testing.
  • Quick mock object creation.

Real-World Uses:

Need a User object in tests but don’t want to hardcode dummy data.
Generate thousands of test objects for performance testing.
Auto-populate sample data for JSON serialization or export.

Step-by-step Java Example:

1. Annotations to Mark Fields for Mocking:

mport java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MockString {
    int length() default 10;
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MockInt {
    int min() default 1;
    int max() default 100;
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MockEmail {}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MockDate {}
Enter fullscreen mode Exit fullscreen mode

These custom annotations are used to mark fields in a class that need to be auto-filled with mock data:

  • @MockString(length = 10) → Generates a random string of the given length
  • @MockInt(min = 1, max = 100) → Fills the field with a random number between the specified min and max
  • @MockEmail → Creates a simple fake email like user1234@example.com
  • @MockDate → Assigns a random past date using LocalDate

These annotations guide the framework during object creation, telling it what kind of test data to generate for each field.

2. A Java User Class / POJO:

public class User {

    @MockString(length = 8)
    private String username;

    @MockEmail
    private String email;

    @MockInt(min = 18, max = 60)
    private int age;

    @MockDate
    private java.time.LocalDate joinDate;

    // For output purposes
    @Override
    public String toString() {
        return "User{username='%s', email='%s', age=%d, joinDate=%s}"
            .formatted(username, email, age, joinDate);
    }
}
Enter fullscreen mode Exit fullscreen mode

This is a simple Java class with four fields, each marked with a custom annotation to generate test data:

  • @MockString(length = 8) → Generates a random 8-character username.
  • @MockEmail → Creates a fake email like user123@example.com.
  • @MockInt(min = 18, max = 60) → Fills age with a value between 18 and 60.
  • @MockDate → Assigns a random past date.

The toString() method is overridden to easily print and check the generated mock data.

3. TestDataX Generator:

The TestDataX class is the core of the framework. It’s responsible for creating an object and automatically filling its fields with fake data, based on the annotations we used.

import java.lang.reflect.*;
import java.time.LocalDate;
import java.util.Random;

public class TestDataX {

    private static final Random random = new Random();

    public static <T> T generate(Class<T> clazz) {
        try {
            T obj = clazz.getDeclaredConstructor().newInstance();

            for (Field field : clazz.getDeclaredFields()) {
                field.setAccessible(true);

                if (field.isAnnotationPresent(MockString.class)) {
                    int len = field.getAnnotation(MockString.class).length();
                    field.set(obj, randomString(len));
                }

                if (field.isAnnotationPresent(MockEmail.class)) {
                    String email = "user" + random.nextInt(9999) + "@example.com";
                    field.set(obj, email);
                }

                if (field.isAnnotationPresent(MockInt.class)) {
                    MockInt mi = field.getAnnotation(MockInt.class);
                    int val = random.nextInt(mi.max() - mi.min() + 1) + mi.min();
                    field.set(obj, val);
                }

                if (field.isAnnotationPresent(MockDate.class)) {
                    LocalDate date = LocalDate.now().minusDays(random.nextInt(1000));
                    field.set(obj, date);
                }
            }

            return obj;

        } catch (Exception e) {
            throw new RuntimeException("Failed to generate test data", e);
        }
    }

    private static String randomString(int length) {
        String chars = "abcdefghijklmnopqrstuvwxyz";
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            sb.append(chars.charAt(random.nextInt(chars.length())));
        }
        return sb.toString();
    }
}
Enter fullscreen mode Exit fullscreen mode

How It Works (Step-by-Step):
Creates an object using reflection: It calls the class’s no-arg constructor to create a new instance.

T obj = clazz.getDeclaredConstructor().newInstance();
Enter fullscreen mode Exit fullscreen mode

Scans all fields in the class: It loops through each field and checks if it has any of the custom annotations like @MockString, @MockInt, etc.

Fills fields with fake values based on annotations:

  • @MockString → Fills the field with a random string of given length
  • @MockEmail → Fills with a fake email like user273@example.com .
  • @MockInt → Generates a random number between min and max .
  • @MockDate → Picks a random date from the past.

Sets the generated value into the field: It uses field.set(obj, value) to insert the fake data into the object.

Returns the fully filled object: At the end, you get a complete object ready to use in your tests or UI.

4. Run and See the Magic:

public class Main {
    public static void main(String[] args) {
        User u1 = TestDataX.generate(User.class);
        User u2 = TestDataX.generate(User.class);

        System.out.println(u1);
        System.out.println(u2);
    }
}
Enter fullscreen mode Exit fullscreen mode

sample output:

User{username='dfaksljd', email='user8311@example.com', age=29, joinDate=2022-12-17}
User{username='aodjrkla', email='user1297@example.com', age=43, joinDate=2023-04-08}
Enter fullscreen mode Exit fullscreen mode

Uses of this framework:

  • Its Not about validation/masking Instead auto-generates values.
  • Extremely useful for testing.
  • Builds clean POJOs.
  • Not dependent on external libraries like Faker and Lombok, just pure Java.

Final Thoughts:

TestDataX may be small, but it solves a real problem and making test data creation effortless.

With just a few lines of code and some clever use of annotations, you’ve built a mini version of what professional libraries like Faker or Java’s Bean Generators do. More importantly, you’ve learned how reflection can help you build flexible tools that work across any Java class.

This framework is a great starting point if you want to:
Learn how modern testing tools work under the hood.
Avoid repeating the same dummy data in every test.
Customize and extend data generation your way.
The best part? You now have full control over how your test data looks and behaves. And as your application grows, you can keep adding features like nested object generation, JSON output, and even file export.

Top comments (0)