[Open Source] A Powerful and Easy-to-Use Data Population Framework That Handles Property Mapping Requirements with Just a Few Annotations
![[Open Source] A Powerful and Easy-to-Use Data Population Framework That Handles Property Mapping Requirements with Just a Few Annotations](https://yy123.ink/api/img/1782592185132-4gpyb2.jpg)
1. Project Overview

Crane4j
A simple and easy-to-use data mapping framework that quickly populates related fields based on foreign keys or code values through simple annotation-based configuration. Supports multiple data sources, including dictionaries, enums, and methods.
A powerful and easy-to-use data population framework that handles all your needs involving "retrieving B using the key value of A, then mapping B's properties to A" with just a few annotations.
2. Open Source License
Licensed under Apache-2.0
3. Screenshots

4. Feature Overview
What Is It?
In our daily development work, we often face tedious data assembly tasks:Retrieving related data based on the value of a specific property of an object and mapping it to another object's properties. These requirements often involve dictionary entries, configuration items, enum constants, and even database table queries. Such data population tasks are often time-consuming and labor-intensive, and they tend to generate repetitive boilerplate code that can be frustrating to maintain.
crane4j was created to solve these frustrations. It is an annotation-driven data population framework. With simple annotation-based configuration, crane4j can elegantly and efficiently handle field population across different data sources, types, and naming conventions, allowing you to focus on core business logic without being distracted by tedious data assembly tasks.
What Features Does It Offer?
- Support for Multiple Data Sources: Supports enums, key-value caches, and methods as data sources. Additional data source types can be supported through simple custom extensions. Caching is also available for all data sources;
- Powerful Field Mapping Capabilities: Automatically maps and converts fields of different types through annotations. It also supports features such as templates, sorting, grouping, and nested object population;
- Highly Extensible: Users can freely replace all major components. Combined with Spring's dependency injection, this enables easy and elegant custom extensions;
- Rich Optional Features: Provides optional features such as automatic population of method return values and method parameters, multithreaded population, custom annotations and expressions, and database framework plugins;
- Plug and Play: Easily integrates with spring/springboot through simple configuration and can also be used in non-spring environments;
5. Tech Stack
Quick Start
Add the Dependency
<dependency>
<groupId>cn.crane4j</groupId>
<artifactId>crane4j-spring-boot-starter</artifactId>
<version>${last-version}</version>
</dependency>
Enabling the Framework
Add @EnableCrane4j to your main application class or configuration class to enable auto-configuration. You can also configure the scanning paths for enum and constant classes here:
@EnableCrane4j(
constantPackages = "com.example.demo", // Scan constant classes
enumPackages = "com.example.demo" // Scan enum classes
)
@SpringBootApplicationpublic
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Configuring Data Sources
crane4j can usemethods, enums, constants, expressions, various ORM frameworks, and even the objects being populated themselves as data sources. Here, we use methods, enums, and constants as examples:
@Component
public void OperationDataSource {
// 1. Use an instance method directly as the "method" data source
@ContainerMethod(namespace = "method", resultType = Foo.class)
public List<Foo> getFooList(Set<Integer>ids) {
return ids.stream()
.map(id -> new Foo(id).setName("foo" + id))
.collect(Collectors.toList());
}
// 2. Use a scanned enum class as the "enum" data source
@ContainerEnum(namespace = "enum", key = "code")
@Getter
@RequiredArgsConstructor
public enum Gender {
MALE(1, "Male"),
FEMALE(0, "Female");
private final Integer code;
private final String name;
}
// 3. Use a scanned constant class as the "constant" data source
@ContainerConstant(namespace = "constant", reverse = true)
public static final class Constant {
public static final String A = "1";
public static final String B = "2";
public static final String C = "3";
}
}
Declaring Population Operations
Simply add annotations to fields to declare population operations based on the data sources configured above. Supports one-to-one, one-to-many, and even many-to-many property mappings:
@Data
@Accessors(chain = true)
@RequiredArgsConstructor
public static class Foo {
// 1. Retrieve the corresponding object from the method based on the id, then map its name to the current name field
@Assemble(container = "method", props = @Mapping("name"))
private final Integer id;
private String name;
// 2. Map its own name property to fooName
@Assemble(props = @Mapping(src = "name", ref = "fooName"))
private String fooName;
// 3. Retrieve the corresponding enum object based on gender, then map its name property to the current genderName field
@Assemble(
container = "enum", props = @Mapping(src = "name", ref = "genderName")
)
private Integer gender;
private String genderName;
// 4. Retrieve corresponding values from constants in batches based on the set of keys, then map them in batches to the current values field
@Assemble(
container = "constant", props = @Mapping(ref = "values"),
handlerType = ManyToManyAssembleOperationHandler.class
)
private Set<String> keys;
private List<String> values;
}
Executing Data Population
Use OperateTemplate to quickly complete data population. You can also add @AutoOperate to a method to automatically populate its return value. Here, we use manual population as an example:
@Autowired
public OperateTemplate operateTemplate; // Inject the utility class for quick data population
public void doOperate() {
List<Foo> targets = IntStream.rangeClosed(1, 2)
.mapToObj(id -> new Foo(id)
.setGender(id & 1)
.setKeys(CollectionUtils.newCollection(LinkedHashSet::new, "1", "2", "3"))
).collect(Collectors.toList());
// Populate objects
operateTemplate.execute(targets);
}
Result:
[
{
"id": 1,
"name": "foo1",
"fooName": "foo1",
"gender": 1,
"genderName": "Male",
"keys": ["1", "2", "3"],
"values": ["A", "B", "C"]
},
{
"id": 2,
"name": "foo2",
"fooName": "foo2",
"gender": 0,
"genderName": "Female",
"keys": ["1", "2", "3"],
"values": ["A", "B", "C"]
}
]
These are the simplest steps for using crane4j in a Spring Boot environment. For more usage examples, please refer to the official documentation.
[Free Book Giveaway]
Win a Book in Our Giveaway, with Free Shipping to Your Door!
Thank you for being with us throughout this journey!
Please visit the [Yifei Open Source] official WeChat account for details.
