Beanknife
An annotation processor library to automatically generate the data transfer objects (DTO).
Install / Use
/learn @vipcxj/BeanknifeREADME
BeanKnife
[![Maven Release][maven-shield]][maven-link]
An annotation processor library to automatically generate the data transfer objects (DTO).
Docs
Quick Look
Base on
class Pojo1 {
private int a;
private List<Pojo2> pojo2List;
}
class Pojo2 {
private String b;
private Pojo1 pojo1;
}
Beanknife is able to generate
class Pojo1View1 {
private int a;
private List<Pojo2View1> pojo2List;
}
class Pojo2View1 {
private String b;
}
Or
class Pojo2View2 {
private String b;
private Pojo1View2 pojo1;
}
class Pojo1View2 {
private int a;
}
Requirement
Jdk 1.8+ (include jdk 1.8)
Quick Start
This library is an annotation processor. Just use it like any other annotation processor.
You will need beanknife-runtime-${version}.jar in your runtime classpath,
and you will need beanknife-core-${version}.jar in your annotation-processor classpath.
In fact, only The PropertyConverter interface in the beanknife-runtime-${version}.jar need be in runtime classpath,
all others just need in compile classpath. In the future, I may split them.
In Maven, you can write:
<dependencies>
<dependency>
<groupId>io.github.vipcxj</groupId>
<artifactId>beanknife-runtime</artifactId>
<version>${beanknife.version}</version>
</dependency>
</dependencies>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.github.vipcxj</groupId>
<artifactId>beanknife-core</artifactId>
<version>${beanknife.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
Introduction
What's the problem?
When writing a web service, we always need to transmit data to the client. We generally call this data objects as DTO(Data Transfer Object. Many of them have similar formats and are derived from some internal data objects of the server, such as database entity classes. But according to the specific needs of the service, they are slightly different. Writing the corresponding DTO for each service is boring and tedious. And in many cases, DTO needs to be maintained synchronously with the corresponding server internal classes. For example, when the internal class of the server has a new attribute, the corresponding DTO will also need the corresponding attribute. Maintaining this relationship manually is tedious and error-prone. So many people simply omit the DTO and use the server internal classes directly. But most of the time this is not a good practice. Server internal classes often have many and complete attributes, but a service may not need so many attributes. So this will bring additional bandwidth consumption. To make matters worse, DTO must be serializable, such as converting to json. But some internal classes are difficult to serialize. For example, there are circular references, or very large deep references. The workaround for many people is to customize its serialization process by configuring the json library. But even jackson, the most widely used json library in the java world, is not doing very well in this regard. Based on the above facts, I brought you this library <b>BeanKnife</b>
What can <b>BeanKnife</b> do for you?
Basically, <b>BeanKnife</b> will generate the DTO automatically for you. You just need to tell the library which you need and which you not need by annotation. Furthermore, it has these powerful features:
- Automatically generate meta class which include all the property names of the target class. You can use these property names in the configure annotation to avoid spelling mistakes.
- This is a non-invasive library. You can let the target class alone and put the annotation on any other class. Of course, directly put the annotation on the target class is also supported.
- You can define the new property in the DTO class. It should be configured on the class other than the target class.
- Support converter, which convert from one type to another type or a type to itself. The runtime library provide some built-in converters. Such as converting a number object to zero when it is null.
- You can override the existed property. It should be configured on the class other than the target class. You can change the property type by converter or replace it with the DTO version. Furthermore, you can rewrite the property.
- Automatically convert the property to its DTO version, when you override it with the DTO type.
The convert feature support Array, List, Set, Stack and Map of the DTO too. And it even support more complex combination such as
List<Map<String, Set<DTO>[]>>[][]
Basics
import io.github.vipcxj.beanknife.runtime.annotations.ViewOf;
@ViewOf(includePattern=".*") // (1)
public class SimpleBean {
private String a;
private Integer b;
private long c;
public String getA() {
return a;
}
public Integer getB() {
return b;
}
public long getC() {
return c;
}
}
- Annotated the class with
@ViewOfand set the appropriate attributeincludePattern. Then the annotation processor will do what it should do. The attributeincludePatternis regex pattern, means which properties are included. By default, nothing is included. SoincludePattern=".*"is necessary here, or the generated class will has no properties.
Above configure will generate:
import io.github.vipcxj.beanknife.runtime.annotations.internal.GeneratedMeta;
@GeneratedMeta(
targetClass = SimpleBean.class,
configClass = SimpleBean.class,
proxies = {
SimpleBean.class
}
)
public class SimpleBeanMeta {
public static final String a = "a";
public static final String b = "b";
public static final String c = "c";
}
and
import io.github.vipcxj.beanknife.runtime.annotations.internal.GeneratedView;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
@GeneratedView(targetClass = SimpleBean.class, configClass = SimpleBean.class)
public class SimpleBeanView {
private String a;
private Integer b;
private long c;
public SimpleBeanView() { }
public SimpleBeanView(
String a,
Integer b,
long c
) {
this.a = a;
this.b = b;
this.c = c;
}
public SimpleBeanView(SimpleBeanView source) {
this.a = source.a;
this.b = source.b;
this.c = source.c;
}
public static SimpleBeanView read(SimpleBean source) {
if (source == null) {
return null;
}
SimpleBeanView out = new SimpleBeanView();
out.a = source.getA();
out.b = source.getB();
out.c = source.getC();
return out;
}
public static SimpleBeanView[] read(SimpleBean[] sources) {
if (sources == null) {
return null;
}
SimpleBeanView[] results = new SimpleBeanView[sources.length];
for (int i = 0; i < sources.length; ++i) {
results[i] = read(sources[i]);
}
return results;
}
public static List<SimpleBeanView> read(List<SimpleBean> sources) {
if (sources == null) {
return null;
}
List<SimpleBeanView> results = new ArrayList<>();
for (SimpleBean source : sources) {
results.add(read(source));
}
return results;
}
public static Set<SimpleBeanView> read(Set<SimpleBean> sources) {
if (sources == null) {
return null;
}
Set<SimpleBeanView> results = new HashSet<>();
for (SimpleBean source : sources) {
results.add(read(source));
}
return results;
}
public static Stack<SimpleBeanView> read(Stack<SimpleBean> sources) {
if (sources == null) {
return null;
}
Stack<SimpleBeanView> results = new Stack<>();
for (SimpleBean source : sources) {
results.add(read(source));
}
return results;
}
public static <K> Map<K, SimpleBeanView> read(Map<K, SimpleBean> sources) {
if (sources == null) {
return null;
}
Map<K, SimpleBeanView> results = new HashMap<>();
for (Map.Entry<K, SimpleBean> source : sources.entrySet()) {
results.put(source.getKey(), read(source.getValue()));
}
return results;
}
public String getA() {
return this.a;
}
public Integer getB() {
return this.b;
}
public long getC() {
return this.c;
}
}
SimpleBeanMeta is the meta bean which list all the available property in SimpleBean.
Here 'available' means all properties except private properties will be listed.
The protected and package properties are included as well because they can be accessed by the classes in same package.
The usage of the generated meta bean will be shown in next example.
SimpleBeanView is the generated DTO class.
It always has a static read method to create a ins
Related Skills
openhue
345.9kControl Philips Hue lights and scenes via the OpenHue CLI.
sag
345.9kElevenLabs text-to-speech with mac-style say UX.
weather
345.9kGet current weather and forecasts via wttr.in or Open-Meteo
tweakcc
1.6kCustomize Claude Code's system prompts, create custom toolsets, input pattern highlighters, themes/thinking verbs/spinners, customize input box & user message styling, support AGENTS.md, unlock private/unreleased features, and much more. Supports both native/npm installs on all platforms.
