3

In what way can Java generate a Bean (not just a Map object)--a bean with fields, getters, and setters from a JSON String.

Here's the code I am trying now using ByteBuddy (non-working code/error):

        Object contextObject = new ByteBuddy()
            .subclass(Object.class)
            .defineField("date", String.class, Modifier.PUBLIC)
            .defineMethod("getDate", Void.TYPE, Modifier.PUBLIC)
            .intercept(FieldAccessor.ofField("date"))
            .make()
            .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
            .getLoaded()
            .newInstance();
        BeanUtils.setProperty(contextObject, "date", "August 1, 2017");

However, due to the "wired" natured for ByteBuddy, I am not sure how flexible it can be to generate a dynamic bean from JSON.

quarks
  • 33,478
  • 73
  • 290
  • 513
  • If you don't know the structure of the JSON ahead of runtime, what value is there in creating a custom object for it? – Preston Garno Aug 21 '17 at 16:03
  • The dynamically generated bean will be used as INPUT for a library, this is the reason. – quarks Aug 21 '17 at 16:08
  • You can dynamically create an object with different fields with ByteBuddy, just add some logic (you won't be able to do it in one shot like the example). For JSON you'd need to recursively create classes to account for the nested objects – Preston Garno Aug 21 '17 at 16:14

2 Answers2

4

Byte Buddy is a generic class generation tool, of course you can define a bean using it. You just need to loop over your properties. Something like the following:

DynamicType.Builder<?> builder = ...
for ( ... ) {
  Class<?> type = ...
  String name = ...
  builder = builder.defineField(name, type, Visibility.PRIVATE)
                   .defineMethod("get" + name, type, Visibility.PUBLIC)
                   .intercept(FieldAccessor.ofBeanProperty())
                   .defineMethod("set" + name, void.class, Visibility.PUBLIC)
                   .withParameters(type)
                   .intercept(FieldAccessor.ofBeanProperty());
}

This has become such a common request that I have added a convenience method to the builder API for the next release:

DynamicType.Builder<?> builder = ...
for ( ... ) {
  Class<?> type = ...
  String name = ...
  builder = builder.definedProperty(name, type);
}
Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192
0

The solution is to use https://github.com/cglib/cglib:

        BeanGenerator beanGenerator = new BeanGenerator();
        beanGenerator.addProperty("date", String.class);
        Object myBean = beanGenerator.create();
        Method setter = myBean.getClass().getMethod("setDate", String.class);
        setter.invoke(myBean, "August 1, 2017");

This code works.

quarks
  • 33,478
  • 73
  • 290
  • 513