I am trying to use inheritence and generics to create my application, but it doesn't seem to work the way I expect it to. I'll show you what I mean (TL;DR at the bottom):
public interface IModel extends Serializable {
public int save();
public void update();
public void delete();
}
// <T> is a JPA annotated entity/class
#SuppressWarnings("serial")
public abstract class Model<T> implements IModel {
private final Repository<T> _repository;
protected T _entity;
public Model(T entity, Repository<T> repository) {
this._entity = entity;
this._repository = repository;
}
public int save() {
return _repository.save(_entity);
}
...
}
This is implemented in for example my AccountModel, which is a Model with generic Account (which is a JPA entity) and which implements IAccount.
public class AccountModel extends Model<Account> implements IAccount {
private static final AccountRepository REPOSITORY = new AccountRepository();
public AccountModel(Account entity) {
super(entity, REPOSITORY);
}
// Method implementations...
}
My generic Repository looks like this:
public abstract class Repository<T> implements Serializable {
private static SessionFactory SESSION_FACTORY;
private final Class<T> _repositoryClass;
private static boolean _initiated = false;
public Repository(Class<T> repositoryClass) {
if (!Repository._initiated)
setup();
this._repositoryClass = repositoryClass;
}
private void setup() {
// logics
Repository._initiated = true;
}
public final Model<T> getById(int id) {
Session session = SESSION_FACTORY.openSession();
try {
session.beginTransaction();
T t = session.get(_repositoryClass, id);
return new Model<T>(t, this); // As suggested by #Vlad
}
finally {
session.close();
}
}
}
The account implementation of this abstract Repository is:
public class AccountRepository extends Repository<Account> {
public AccountRepository() {
super(Account.class);
}
public Model<Account> getByEmail(String emailAddress) {...}
}
So far so good, this is all working as expected. But I cannot use a Model<T> as a TModel.
TL;DR
I would like use the following line of code:
AccountModel account = new AccountRepository().getById(1);
Since AccountModel inherits Model<Account> and new AccountRepository().getById() always returns Model<Account> I expect this to work, but it doesn't.
What am I missing?
Related
I am trying to implement Strategy pattern approach for payment processing in my Spring webflux based application.
My application supports multiple payment method like, Card Payment, Cash Payment, ...
Also, we have to support Square & Stripe for Card payment.
Model class,
// Model interface
public interface PaymentModel {
}
// Base model with attributes needed for all payment types
public class BaseModel implements PaymentModel {
private Float amount;
private Integer userId;
}
public class SquareCardModel extends BaseModel {
private String merchantId;
private String device;
private String orderId;
}
public class StripeCardModel extends BaseModel {
private String merchantId;
private String orderId;
}
public class CashModel extends BaseModel {
private String name;
private String orderId;
}
Service Class,
#Service
public interface PaymentService<T extends PaymentModel> {
Mono<ServerResponse> pay(T model);
String method();
}
#Service
public class CashPaymentService implements PaymentService<CashModel> {
private static final String PAYMENT_METHOD = "cash";
#Override
public Mono<ServerResponse> pay(CashModel model) {
// TODO Auto-generated method stub
return null;
}
#Override
public String method() {
return PAYMENT_METHOD;
}
}
#Service
public class SquarePaymentService implements PaymentService<SquareCardModel> {
private static final String PAYMENT_METHOD = "cash";
#Override
public Mono<ServerResponse> pay(SquareCardModel model) {
// TODO Auto-generated method stub
return null;
}
#Override
public String method() {
return PAYMENT_METHOD;
}
}
#Service
public class StripePaymentService implements PaymentService<StripeCardModel> {
private static final String PAYMENT_METHOD = "cash";
#Override
public Mono<ServerResponse> pay(SquareCardModel model) {
// TODO Auto-generated method stub
return null;
}
#Override
public String method() {
return PAYMENT_METHOD;
}
}
Factory Class,
#Service
public class PaymentFactory<T> {
private final List<PaymentService<? extends PaymentModel>> paymentServices;
#Autowired
public PaymentFactory(List<PaymentService<? extends PaymentModel>> paymentServices) {
this.paymentServices = paymentServices;
}
public PaymentService<? extends PaymentModel> retrievePaymentService(final String paymentMethod) {
Optional<PaymentService<? extends PaymentModel>> paymentService = paymentServices.stream()
.filter(service -> service.method().equals(paymentMethod)).findFirst();
if (paymentService.isEmpty()) {
throw new IllegalArgumentException("Unsupported Payment method ");
}
return paymentService.get();
}
}
User choose the payment method and the call comes to the backend,
#Transactional
public Mono<ServerResponse> payBilling(ServerRequest request) {
return request.bodyToMono(PaymentDto.class).flatMap(paymentReq -> {
if (paymentReq.getPaymentType().equals("CC")) { // For Card
return processCardPayment(usr, paymentReq);
} else {
return badRequest().bodyValue("Not supported yet !");
}
});
}
private Mono<? extends ServerResponse> processCardPayment(
PaymentDto paymentReq) {
PaymentService<PaymentModel> paymentService = (PaymentService<PaymentModel>) paymentFactory
.retrievePaymentService(paymentReq.getPaymentType());
PaymentModel paymentModel = buildPaymentModel((String) paymentReq.getPaymentType(), paymentReq,
jsonMap);
return paymentService.pay(paymentModel);
}
private PaymentModel buildPaymentModel(final String paymentMethod, final PaymentDto paymentReq,
if (paymentMethod.equals("squarePayment")) {
SquareCardModel model = new SquareCardModel();
model.setAmount(paymentReq.getTotal());
model.setMerchantId(paymentReq.getMerchantid());
model.setOrderId(orderId);
return model;
}
return null;
}
Questions:
Not sure if I have implemented generics properly with the strategy pattern.
Also, I dont like type casting here. (PaymentService). is there any better approach?
Why do I still need to use if for creating different model.
if (paymentMethod.equals("squarePayment")) {
PaymentService<PaymentModel> paymentService = (PaymentService<PaymentModel>) paymentFactory
.retrievePaymentService(paymentReq.getPaymentType());
PaymentModel paymentModel = buildPaymentModel((String) paymentReq.getPaymentType(), paymentReq,
jsonMap);
return paymentService.pay(paymentModel);
Here's a simplified version of your code which I think maintains what you need to do, from a type perspective:
import java.util.Optional;
public class App {
public interface PaymentModel { }
public static class CashModel implements PaymentModel { }
public interface PaymentService<T extends PaymentModel> {
void pay(T model);
void pay2(PaymentModel model);
}
public static class PaymentFactory {
public PaymentService<PaymentModel> retrievePaymentService(final String paymentMethod) {
Optional<PaymentService<PaymentModel>> paymentService = null;
return paymentService.get();
}
public PaymentService<? extends PaymentModel> retrievePaymentService2(final String paymentMethod) {
Optional<PaymentService<PaymentModel>> paymentService = null;
return paymentService.get();
}
}
public static void main(String... args) throws NoSuchFieldException, IllegalAccessException {
PaymentFactory paymentFactory = null;
PaymentService<PaymentModel> paymentService = paymentFactory
.retrievePaymentService("foo");
paymentService.pay(new CashModel());
PaymentService<? extends PaymentModel> paymentService2 = paymentFactory
.retrievePaymentService2("foo");
paymentService2.pay(new CashModel()); // error
paymentService2.pay2(new CashModel()); // ok
}
}
Look at the difference between retrievePaymentService and retrievePaymentService2.
retrievePaymentService returns PaymentService<PaymentModel> which says that it is a payment service which works on any PaymentModel implementation.
retrievePaymentService2 returns PaymentService<? extends PaymentModel> which says that it is a payment service which works on some specific, unknown PaymentModel implementation.
As you have already made sure that your PaymentModel type matches the PaymentService you are getting from the factory, the first form is what you want.
A better design might try to not have two parallel class hierarchies which need to be matched up carefully at runtime.
Also, processCardPayment seems as though it should handle all PaymentModels?
I have the following Manager Class with the builder() method:
public class Manager extends Employee {
public static Manager.Builder builder() {
return new ManagerBuilder();
}
public abstract static class Builder<T extends Employee, B extends Builder<T,B>> extends Employee.Builder<T,B>{
}
public static class ManagerBuilder extends Builder<Manager,ManagerBuilder> {
#Override
protected ManagerBuilder self() {
return this;
}
#Override
public Manager build() {
return new Manager(this);
}
}
}
unfortunatelly trying to build an Object with Manager.builder().age(25).build(); return a Person and not a Manager as I need.
How should I change the Manager.builder() return type to return a Manager and at the same time not clashing with the Employee.builder() Method signature.
The code Employee.builder().age(25).build(); returns Employee, which is fine.
The Employee Class is looking like this:
public class Employee extends Person {
public static Employee.Builder<Employee, EmployeeBuilder> builder() {
return new EmployeeBuilder();
}
public abstract static class Builder<T extends Person, B extends Builder<T,B>> extends Person.Builder<T,B>{
}
public static class EmployeeBuilder extends Builder<Employee, EmployeeBuilder> {
#Override
protected EmployeeBuilder self() {
return this;
}
#Override
public Employee build() {
return new Employee(this);
}
}
}
public class Person implements PersonInterface {
private Optional<Integer> age;
protected Person(Builder<?,?> builder) {
this.age = builder.age;
}
public abstract static class Builder<T extends Person, B extends Builder<T,B>> {
private Optional<Integer> age;
protected Builder() {
}
public B age(Integer age) {
if (Objects.isNull(age) || age == 0) throw new IllegalArgumentException("Age ist empty");
this.age = Optional.of(age);
return self();
}
protected abstract B self();
public abstract T build();
}
public static class PersonBuilder extends Builder<Person, PersonBuilder>{
#Override
protected PersonBuilder self() {
return this;
}
#Override
public Person build() {
return new Person(this);
}
}
}
The core problem is your strange inheritance structure which overloads the classname Builder. I cant' quite pin the problem down, but at some point your specific type information of ManagerBuilder is lost. This can be simplyfied a lot:
public class Employee extends Person {
public static EmployeeBuilder builder() {
return new EmployeeBuilder();
}
public static class EmployeeBuilder extends Person.Builder<Employee, EmployeeBuilder> {
#Override
protected EmployeeBuilder self() {
return this;
}
#Override
public Employee build() {
return new Employee(this);
}
}
}
public class Manager extends Employee {
public static ManagerBuilder builder() {
return new ManagerBuilder();
}
public static class ManagerBuilder extends Person.Builder<Manager, ManagerBuilder> {
#Override
protected ManagerBuilder self() {
return this;
}
#Override
public Manager build() {
return new Manager(this);
}
}
}
This should solve a few of your problems.
Now you are left with one more problem. The static method builder is overloaded with incompatible return types. You find information about this at Why does Java enforce return type compatibility for overridden static methods?
If you name those methods differently, it should work.
Well your code works perfectly, and Manager.builder().age(25).build() actually returns a Manager. It is only a compile time problem.
The following Junit test should succeed (it does on my tests):
#Test
public void testEss3() throws Exception {
Person emp = Manager.builder().age(25).build();
assertTrue(emp instanceof Manager);
}
In fact, it looks like as you declare no variable to host the builder, and as the method age is not defined in Manager.Builder nor in its direct subclass Employee.Builder, the Java compiler assume that it will return an object of the class in which it is declared, that is a Person.Builder. It is not false because it is actually an ancestor class. But from that point, the compiler do not know the exact class returned by build() and only knows that it will be a Person.
But the following code is accepter by the compiler:
Manager.Builder<Manager,?> builder = Manager.builder();
Manager emp = builder.age(25).build();
public interface A extends C {
String getCh();
String getId();
String getReview();
}
public interface B extends C {
String getCh();
String getId();
String getReview();
}
#Data
#Builder
public class AImpl implements A{
private String ch;
private String id;
private String review;
}
#Data
#Builder
public class BImpl implements B{
private String ch;
private String id;
private String review;
}
so now to use the builders of these I do:
return AImpl.builder()
.ch("ch")
.id("id")
.review("somerview");
For B I do:
return BImpl.builder()
.ch("ch1")
.id("id1")
.review("some new review");
Is there a way where I can make this builder part into a function? I dont like the idea of repeating the same code again. Like where I can pass id channel and review in a function and I can the object?
Disclaimer: I have never really dealt with builders so there might be a really much better option :D
This approach writes builders for each interface individually.
This does require that the interfaces provide a setter method.
Using generics, the methods of the RootBuilder and BaseABuilder return an instance of the ImplABuilder so that the chain can continue properly.
This is a very simple implementation of the Thistype generic which in other languages exists by default. This implementation also relies on casting to the actual Thistype but if you set the generics properly, that shouldnt be an issue.
public class Test
{
public static void main(String[] args)
{
ImplA implA = ImplA
.builder()
.id("id")
.description("description")
.valueA("a")
.build();
}
}
public interface Root
{
String getId();
void setId(String id);
String getDescription();
void setDescription(String description);
}
public class RootBuilder<Thistype extends RootBuilder<Thistype, Instance>, Instance extends Root>
{
protected final Instance object;
RootBuilder(Instance object)
{
this.object = object;
}
public Thistype id(String value)
{
object.setId(value);
return (Thistype)this;
}
public Thistype description(String value)
{
object.setDescription(value);
return (Thistype)this;
}
public Instance build()
{
return object;
}
}
public interface BaseA extends Root
{
String getValueA();
void setValueA(String valueA);
}
public class BaseABuilder<Thistype extends BaseABuilder<Thistype, Instance>, Instance extends BaseA> extends RootBuilder<Thistype, Instance>
{
protected Instance object;
BaseABuilder(Instance object)
{
super(object);
}
public Thistype valueA(String value)
{
object.setValueA(value);
return (Thistype)this;
}
}
public interface BaseB extends Root
{
String getValueB();
void setValueB(String valueB);
}
public interface BaseC extends Root
{
String getValueC();
void setValueC(String valueC);
}
public final class ImplA implements BaseA
{
private String id;
private String description;
private String valueA;
private ImplA() { }
public static ImplABuilder builder()
{
return new ImplABuilder(new ImplA());
}
private static class ImplABuilder extends BaseABuilder<ImplABuilder, ImplA> // assuming ImplA is final
{
ImplABuilder(ImplA object)
{
super(object);
}
// additional methods for ImplA class
}
}
I am little confused how to avoid using casing in my manager method (last snippet of code) in terms of abstract class with it's derived classes (entities) and visitor design pattern eventually. Below I have an abstract class for entities called BaseEntity. It's not a real example, just pseudocode.
public abstract class BaseEntity {
#Reference
protected List<String> items = new ArrayList<>();
public BaseEntity() {
}
public List<String> getItems() {
return items;
}
public void setItems(List<String> items) {
this.items = items;
}
}
Below I have 3 derived classes from abstract class.
#Entity("CollectionA")
public class EntityA extends BaseEntity {
//code
}
#Entity("CollectionB")
public class EntityB extends BaseEntity {
//code
}
#Entity("CollectionC")
public class EntityC extends BaseEntity {
//code
}
Then I created an visitor to reuse that in my manager to avoid using instanceOf.
public interface UpdateEntityVisitor {
void create(EntityA entityA);
void create(EntityB entityB);
void create(EntityC entityC);
}
public class UpdateEntityVisitorImpl implements UpdateEntityVisitor {
private final Factory factory;
public UpdateEntityVisitorImpl() {
factory = new FactoryImpl();
}
public UpdateEntityVisitorImpl(Factory factory) {
this.factory = factory;
}
#Override
public void create(EntityA entityA) {
factory.getEntityA().create(entityA);
}
#Override
public void create(EntityB entityB) {
factory.getEntityB().create(entityB);
}
#Override
public void create(EntityC entityC) {
factory.getEntityC().create(entityC);
}
}
And finally it's my manager class which has below method, where I would like to avoid casting down from BaseEntity to appropriate classes. There is a way to achieve that reusing above visitor class in manager ?
public void updateEntity(BaseEntity entity) {
if (checkSmth()) {
updateCollectionA((EntityA) entity);
} else {
updateCollectionB((EntityB) entity);
}
}
I found this very useful library called typeOf https://github.com/nurkiewicz/typeof but I was wondering if there is other way to make it more clear to my current team.
Does using generics work?
public <T extends BaseEntity> void updateEntity(T entity)
{
if (checkSmth())
updateCollectionA(entity);
else
updateCollectionB(entity);
}
Am developing webapplication with JSF and Hibernate, have Entity, Entity data access & JSF managed bean classes in following pattern and same repeats in all the classes. Since all the classes have the same pattern, I would like to make it as abstract class.
Entity Class
public class MyEntity {
-----
-----
}
Data Access class
public class MyEntityDAO extends AbstractDAO<MyEntity> {
MyEnitityDAO(){
-------
}
}
JSF Managed bean
public class MyBean implements Serializable {
private static final long serialVersionUID = 1L;
private MyEntity current;
private MyEntityDAO dao;
private DataModel<MyEntity> items = null;
public MyBean() {
// TODO Auto-generated constructor stub
}
public MyEntity getCurrent() {
return current;
}
public void setCurrent(MyEntity current) {
this.current = current;
}
public MyEntityDAO getDao() {
if (dao == null) {
dao = new MyEntityDAO();
}
return dao;
}
public DataModel<MyEntity> getItems() {
return items;
}
public List<MyEntity> getMyEntityList() {
return getDao().findAll();
}
public MyEntity getMyEntity(int id) {
return getDao().findById(id);
}
private void reSetDataModel() {
items = null;
}
private void reSetCurrent() {
setCurrent(null);
}
public void prepareCreate() {
current = new MyEntity();
}
public void create() {
// Save the entity
}
public void edit() {
// Update the entity
}
public void delete() {
// Remove the entity
}
}
How to make the abstract class out of above pattern?
Type the word abstract between public and class