📜 ⬆️ ⬇️

Wicket + lambda: a type-safe and concise implementation of IModel

Standard task when developing a web application: there is a data object, this data is required to be displayed (output in HTML). In Apache Wicket, data for this is tied to components (which will be engaged in mapping) using models (implementing the IModel interface).

Most likely, this publication will be read by those who are already in the know, but just in case: the main method from the IModel that interests us is:

T getObject(); 

Abstraction is simple and concise, but not everything is so simple in practice. Under the cut - a tale about how Java 8 helped defeat the verbosity and insecurity of standard approaches.

Data


Test data class:
 public class User implements Serializable { private final String name; private final int age; public User(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } } 


')

Attempt # 1: we wrote, we wrote ...


Here's how to approach the task:

 public class AbstractReadOnlyModelPanel extends Panel { public AbstractReadOnlyModelPanel(String id, IModel<User> model) { super(id, model); add(new Label("name", new AbstractReadOnlyModel<String>() { @Override public String getObject() { return model.getObject().getName(); } })); add(new Label("age", new AbstractReadOnlyModel<Integer>() { @Override public Integer getObject() { return model.getObject().getAge(); } })); } } 

Everything is cheap, reliable and practical: we create an anonymous subclass of AbstractReadOnlyModel. It works quickly, it looks clear. One problem - due to the use of that same anonymous class, the code is cumbersome: 6 lines per component is not a joke.

Attempt # 2: shoot in the direction of the leg


Now we will try PropertyModel :

 public class PropertyModelPanel extends Panel { public PropertyModelPanel(String id, IModel<User> model) { super(id, model); add(new Label("name", PropertyModel.of(model, "name"))); add(new Label("age", PropertyModel.of(model, "age"))); } } 

Wow, much smaller. But in a barrel of honey there is a lot of tar:



Lambda come on stage


Fortunately, Java 8 has long been released, and lambdas along with Method References are already in a hurry to help:

 public class GetterModel<E, P> extends AbstractReadOnlyModel<P> { private final E entity; private final IModel<E> entityModel; private final IPropertyGetter<E, P> getter; private GetterModel(E entity, IModel<E> entityModel, IPropertyGetter<E, P> getter) { this.entity = entity; this.entityModel = entityModel; this.getter = getter; } public static <E, P> GetterModel<E, P> ofObject(E entity, IPropertyGetter<E, P> getter) { Objects.requireNonNull(entity, "Entity cannot be null"); Objects.requireNonNull(getter, "Getter cannot be null"); return new GetterModel<>(entity, null, getter); } public static <E, P> GetterModel<E, P> ofModel(IModel<E> entityModel, IPropertyGetter<E, P> getter) { Objects.requireNonNull(entityModel, "Entity model cannot be null"); Objects.requireNonNull(getter, "Getter cannot be null"); return new GetterModel<>(null, entityModel, getter); } @Override public P getObject() { return getter.getPropertyValue(getEntity()); } private E getEntity() { return entityModel != null ? entityModel.getObject() : entity; } } 

 public interface IPropertyGetter<E, P> { P getPropertyValue(E entity); } 

Well, immediately an example, rewritten with this implementation of the model:

 public class GetterModelPanel extends Panel { public GetterModelPanel(String id, IModel<User> model) { super(id, model); add(new Label("name", GetterModel.ofModel(model, User::getName))); add(new Label("age", GetterModel.ofModel(model, User::getAge))); } } 

Almost as briefly as in the PropertyModel example, besides:


Compared to the PropertyModel, however, there are some drawbacks:


But there is a nice bonus: an analogue of the magical possibility of using a PropertyModel as a data source and model, and the POJO is implemented without any magic: we simply added two factory methods (ofModel () and ofObject ()).

Links


  1. Apache Wicket Framework
  2. Java: Lambda Expressions
  3. Java: Method References

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


All Articles