We have a POJO that is auto-generated with ~60 properties. This is generated with avro 1.4, which does not include getters/setters.
A library that we use to provide simple transformations between objects requires getter/setter-like methods in order to properly work.
Is there a way to replicate getters/setters without having to manually override the POJO and create all of the getters/setters manually?
public class BigGeneratedPojo {
public String firstField;
public int secondField;
...
public ComplexObject nthField;
}
public class OtherObject {
private String reprOfFirstFieldFromOtherObject;
private ComplexObject reprOfFirstFieldFromOtherObject;
public String getReprOfFirstFieldFromOtherObject() { ... standard impl ... };
public void setReprOfFirstFieldFromOtherObject() { ... standard impl ... };
}
the desire is to write code that looks like:
Mapper<BigGeneratedPojo, OtherObject> mapper =
MagicalMapperLibrary.mapperBuilder(BigGeneratedPojo.class, OtherObject.class)
.from(BigGeneratedPojo::getFirstField).to(OtherObject::reprOfFirstFieldFromOtherObject)
.build();
BigGeneratedPojo pojo = new BigGeneratedPojo();
pojo.firstField = "test";
OtherObject mappedOtherObj = mapper.map(pojo);
assertEquals(mappedOtherObj.getReprOfFirstFieldFromOtherObject(), "test");
The POJO class must be public. It must have a public default constructor. It may have the arguments constructor. All objects must have some public Getters and Setters to access the object values by other Java Programs.
You may use lombok - to manually avoid getter and setter method. But it create by itself. The using of lombok significantly reduces a lot number of code.
Getters and setters can allow different access levels - for example the get may be public, but the set could be protected.
Project Lombok provides @Getter and @Setter annotations which can be used at class level to generate getter and setter methods automatically.
Lombok also has the capability to generate equals and hashcode methods.
Or you can use the @Data
which is according to lombok website:
@Data All together now: A shortcut for @ToString, @EqualsAndHashCode, @Getter on all fields, @Setter on all non-final fields, and @RequiredArgsConstructor!
@Data
public class BigGeneratedPojo {
public String firstField;
public int secondField;
...
public ComplexObject nthField;
}
You can try to generate the proxy beans dynamically, for instance, using BitBuddy: https://bytebuddy.net/
The sample below shows how to proxy a property field of a method. Note that this is only a sample, and most probably you might have to wrap it and add some dynamic using reflections, but I think it's quite an interesting option if you wish to dynamically extend code.
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.FixedValue;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.jar.asm.Opcodes;
import org.apache.commons.beanutils.BeanUtils;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class M1 {
public static class PojoBase {
int property;
String strProp;
}
public static class Intereptor {
private final String fieldName;
private final PojoBase pojo;
public Intereptor(PojoBase pojo, String fieldName) {
this.pojo = pojo;
this.fieldName = fieldName;
}
@RuntimeType
public Object intercept(@RuntimeType Object value) throws NoSuchFieldException, IllegalAccessException {
Field field = pojo.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(pojo, value);
return value;
}
}
public static void main(String... args) throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
PojoBase origBean = new PojoBase();
PojoBase destBean = new PojoBase();
origBean.property = 555666;
origBean.strProp = "FooBar";
DynamicType.Builder<Object> stub = new ByteBuddy()
.subclass(Object.class);
DynamicType.Builder.MethodDefinition.ReceiverTypeDefinition<Object> dynamic = stub.defineMethod("getProperty", Integer.TYPE, Opcodes.ACC_PUBLIC).intercept(FixedValue.value(origBean.property))
.defineMethod("setProperty", Void.TYPE, Opcodes.ACC_PUBLIC).withParameters(Integer.TYPE).intercept(MethodDelegation.to(new Intereptor(destBean, "property")))
.defineMethod("getStrProp", String.class, Opcodes.ACC_PUBLIC).intercept(FixedValue.value(origBean.strProp))
.defineMethod("setStrProp", Void.TYPE, Opcodes.ACC_PUBLIC).withParameters(String.class).intercept(MethodDelegation.to(new Intereptor(destBean, "strProp")));
Class<?> dynamicType = dynamic.make()
.load(M1.class.getClassLoader())
.getLoaded();
Object readerObject = dynamicType.newInstance();
Object writterObject = dynamicType.newInstance();
BeanUtils.copyProperties(readerObject, writterObject);
System.out.println("Out property:" + destBean.property);
System.out.println("Out strProp:" + destBean.property);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With