Too many templates, how can I reduce the number of POJO developers?

I have several different POJOs that use a constructor template , but after adding a builder for each of them and creating Object.toString , Object.hashCode and Object.equals , my classes end up with about 100 lines of code. There must be a better way to handle this. I think that having some kind of reflective builder will help a lot, but I'm not sure that it will be a good practice, and I'm also not sure how exactly this will happen. In other words, is there a way to implement such a constructor?

Simple POJO:

 public class Foo { public int id; public String title; public boolean change; ... } 

Then some reflective builder:

 Foo = ReflectiveBuilder.from(Foo.class).id(1).title("title").change(false).build(); 
+6
source share
4 answers

The short answer is no . What you ask for is impossible. Reflection considers the code at runtime and dynamically calls methods; it cannot generate actual methods.

What could you do:

 Foo foo = ReflectiveBuilder.from(Foo.class). set("id", 1). set("title", "title"). build(); 

This has three massive problems:

  • String fields - a typo causes a runtime error, not a compilation time,
  • Object values ​​- the wrong type causes a runtime error, not a compilation time, and
  • it will be much slower than the alternative, since the reflection is very slow.

Thus, a reflection-based solution, although possible (see Apache Commons BeanUtils BeanMap ), is not at all practical.

Long answer, if you are willing to allow some compile-time magic, you can use Project Lombok . Lombok's idea is to create template code from annotations using the Java annotation preprocessor.

It is truly magical that all IDEs, and at least the big 3, understand that annotation preprocessing and code completion will function correctly even if the code really does not exist.

In the case of POJO with Builder you can use @Data and @Builder

 @Data @Builder public class Foo { public int id; public String title; public boolean change; ... } 

The @Data will generate:

  • necessary argument constructor (which accepts all final fields)
  • equals and hashCode that use all fields (can be customized using the @EqualsAndHashCode annotation)
  • a toString for all fields (can be configured using @ToString annotations and
  • public getters and seters for all fields (can be configured using the @Getter / @Setter in the fields).

The @Builder will generate an inner class called Builder , which can be created using Foo.builder() .

Make sure you configure the equals , hashCode and toString methods as if you had two classes with Lombok that have references to each other, then you end the endless loop in the default case, since both classes include other methods .

There is also a new configuration system that allows you to use, for example, fusible setters, so that you can no longer use if your POJO is changed:

 new Foo().setId(3).setTitle("title)... 

For another approach, you can look at Aspect Oriented Programming (AOP) and AspectJ . AOP allows you to chop your classes into “aspects,” and then stick to them together using specific rules using a pre-compiler. For example, you can accurately implement what Lombok does using custom annotations and aspect. However, this is a rather complicated topic, and it is quite possible to overdo it.

+4
source

Perhaps the Lombok Project (yes, the site is ugly) is an option for you. Lombok injects code into your classes based on annotations.

In Lombok, you use @Data annotations for generated getters, setters, toString() , hashCode() and equals() :

 @Data public class Foo { public int id; public String title; public boolean change; } 

Take a look at the example in the @ section of the documentation to see the generated code.

Lombok also provides @Builder , which creates a builder for your class. But keep in mind that this is an experimental function:

 @Builder public class Foo { public int id; public String title; public boolean change; } 

Now you can do:

 Foo foo = Foo.builder() .id(123) .title("some title") .change(true) .build(); 
+4
source

I personally use this website to create all the template code for POJO for me. All you have to do is insert the JSON that you want to parse and it will generate all the classes for you. Then I just use Retrofit to query / cache / analyze the information. Here is an example of Retrofit and POJO in my Github account. Hope this helps!

+1
source

I created a small CakeMold library to do the current POJO initialization. He uses reflection, which, of course, is not fast. But it can be very useful when you need to write tests.

 Person person = CakeMold.of(Person.class) .set("firstName", "Bob") .set("lastName", "SquarePants") .set("email", " sponge.bob@bikinibottom.io ") .set("age", 22) .cook(); 
0
source

Source: https://habr.com/ru/post/975698/


All Articles