Open Session in View or DTO solution - spring

I was wondering if this recipe does not use Open Session in View or Dozer works (the scenario is a spring, jsf, hibernate application):
I have this in back-end module:
public abstract class AbstractMap<E extends Serializable> implements Mapper<E> {
public abstract E map(E e) ;
public List<E> map(List<E> l) {
List<E> map = new ArrayList<E>();
for (E t : l) {
map.add(this.map(t));
}
return map;
}
}
#Component
public class PersonService extends AbstractService<Person>{
#Autowired
PersonDAO personDao;
#Transacted
public List<Person> findPeople(Mapper<Person> m, PersonFilter filter) {
return m.map(personDao.findByFilter(filter));
}
}
In front-end I have this jsb bean:
#Component
#Scope("session")
public class PersonBean {
#Autowired
PersonService personService;
PersonFilter personFilter;
List<Person> getPeople() {
return personService.findPeople(new AbstractMap<People>() {
public Person map(Person person) {
Person dto = new Person();
dto.setName(person.getName());
dto.setAddresses(new AbstractMap<Address>() {
public Address map(Address a) {
Address dto = new Address();
dto.setStreet(a.getStreet());
return dto;
}
}.map(person.getAddresses()));
return dto;
}
}, personFilter);
}
}
From my point of view has some advantages:
front-end must to indicate that it want to retrieve every invocation to back-end.
if need use a mapper in more than a place, I can move map code to a external class.
back-end open and close transaction.
don't need duplicate code to define DTOs for Person and Address.
What problems that could cause this proposed solution?

Related

How inject list of bean in Quarkus?

I try to implement chain of responsibility with quarkus 2.10.0.
I have class IssueChangeChain and no one IssueChangeChainLink doesn't inject in field links.
#ApplicationScoped
public class IssueChangeChain {
#Inject
#All
List<IssueChangeChainLink> links;
public void processIssueChange(JiraChangeDTO change) {
logger.info("Try to process " + change + " through " + links);
if(change == null)
return;
links.forEach(link ->{
var changeItem = link.getChangeItem(change);
if (changeItem != null) {
link.processChangeItem(changeItem);
}
});
}
void setLinks(List<IssueChangeChainLink> links) {
this.links = links;
}
}
And three classes implemented IssueChangeChainLink
#ApplicationScoped
public class IssueCreationChainLink implements IssueChangeChainLink<AddJiraIssueDTO> {
#Override
public AddJiraIssueDTO getChangeItem(JiraChangeDTO change) {
...
}
#Override
public void processChangeItem(AddJiraIssueDTO changeItem) {
...
}
private static final Logger log = LoggerFactory.getLogger(IssueCreationChainLink.class);
}
#ApplicationScoped
public class SprintChangeChainLink implements IssueChangeChainLink<IssueAddSprintDTO> {
#Override
public IssueAddSprintDTO getChangeItem(JiraChangeDTO change) {
...
}
#Override
public void processChangeItem(IssueAddSprintDTO changeItem) {
...
}
private static final Logger log = LoggerFactory.getLogger(SprintChangeChainLink.class);
}
What should I do to inject List of beans?
#Inject
List<?> instances;
does not work in Quarkus as this is not supported in CDI. In CDI it is looking for a bean which is a List.
What you should do is inject
#Inject
#All
Instance<IssueChangeChainLink> instances;
Instance from CDI implements Iterable, which you can then use .stream() or .forEach() from to iterate over beans.

Spring JPA : REQUIRES_NEW propagation not working

I have the following scenario where I have one controller containing two functions (saveAudit and saveProduct). Each one persists an object,I would like to separate transactions between those functions.
throwed exception on saveProduct function should not rollback transaction on saveAudit function :
My repositories/ DAO :
public interface AuditRepository extends JpaRepository<Audit, String> {
}
public interface ProductRepository extends JpaRepository<Product, String> {
}
My controller:
#RestController
#Transactional
public class ProductController {
private final ProductreRepository productRepository;
private final Auditrepository auditRepository;
#Transactional(propagation=Propagation.REQUIRES_NEW)
void saveAudit()
{
auditRepository.saveAudit(Audit.builder().action("action1").build());
}
#PostMapping(ApiPaths.PRODUCTS)
#ResponseStatus(HttpStatus.CREATED)
public ProductDTO addNewProduct() {
ProductDTO res = productRepository.saveProduct(Product.builder().label("product1").build());
saveAudit();
int h=1/0; // => throw exception to rollback product creation
return res;
}
}
Logs:
Participating in existing transaction
its same class proxy will not work.
move below method to #Service class and inject in your controller or annotate #Transactional(propagation=Propagation.REQUIRES_NEW) in auditRepository.saveAudit
#Transactional(propagation=Propagation.REQUIRES_NEW)
public void saveAudit()
{
auditRepository.saveAudit(Audit.builder().action("action1").build());
}

Spring MVC instantiate object on request attribute

Assume I am creating a PrinterService class that has a AbstractPrinter object. AbstractPrinter is subclassed by classes such as HPPrinter, FilePrinter etc.
The exact kind of printer object to be used is mentioned in the RequestParam object passed to my Controller (it is a request attribute).
Is there any way I can inject the right kind of concrete printer class using Spring?
All the other dependencies are injected using #Autowired annotation. How to inject this one?
You can create and load a factory of AbstractPrinter objects during container startup as shown below and dynamically call the respective the AbstractPrinter's print() (or your own method) based on the input parameter (comes from controller) to the service.
In the below code for PrinterServiceImpl class, the main point is that all of the List<AbstractPrinter> will be injected by Spring container (depends upon how many implementation classes you provide like HPPrinter, etc..). Then you will load those beans into a Map during container startup with printerType as key.
#Controller
public class YourController {
#Autowired
private PrinterService printerService;
public X myMethod(#RequestParam("input") String input) {
printerService.myServiceMethod(input);
//return X
}
}
PrinterServiceImpl class:
public class PrinterServiceImpl implements PrinterService {
#Autowired
private List<AbstractPrinter> abstractPrinters;
private static final Map<String,AbstractPrinter> myPrinters = new HashMap<>();
#PostConstruct
public void loadPrinters() {
for(AbstractPrinter printer : abstractPrinters) {
myPrinters.put(printer.getPrinterType(), printer);
}
}
//Add your other Autowired dependencies here
#Override
public void myServiceMethod(String input){//get input from controller
AbstractPrinter abstractPrinter= myPrinters.get(input);
abstractPrinter.print();//dynamically calls print() depending on input
}
}
HPPrinter class:
#Component
public class HPPrinter implements AbstractPrinter {
#Override
public String getPrinterType() {
return "HP";
}
#Override
public void print() {
// Your print code
}
}
FilePrinter class:
#Component
public class FilePrinter implements AbstractPrinter {
#Override
public String getPrinterType() {
return "FILE";
}
#Override
public void print() {
// Your print code
}
}
You could create a dedicated PrinterService instance per AbstractPrinter concrete class. For example you could achieve this using Spring configuration which follow the factory pattern:
#Configuration
public class PrinterServiceConfiguration {
#Autowired
private HPPrinter hpPrinter;
#Autowired
private FilePrinter filePrinter;
#Bean
public PrinterService hpPrinterService() {
return new PrinterService(hpPrinter);
}
#Bean
public PrinterService filePrinterService() {
return new PrinterService(filePrinter);
}
public PrinterService findPrinterService(PrinterType type){
if (type == HP)
return hpPrinterService();
....
}
}
Then in your controller, inject PrinterServiceConfiguration then call findPrinterService with the right printer type.
Don't forget to add PrinterServiceConfiguration at your configuration #Import.
If the list of printer is dynamic you could switch to prototype bean :
#Configuration
public class PrinterServiceConfiguration {
#Autowired
private List<AbstractPrinter> printers;
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public PrinterService createPrinterService(PrinterType type){
return new PrinterService(findPrinterByType(type));
}
private Printer findPrinterByType(PrinterType type) {
// iterate over printers then return the printer that match type
// throw exception if no printer found
}
}

How to achieve a dynamic dependency injection in spring?

We have a scenario where the dependency should be determinded at runtime. An example shows the detail below:
public class OrderProcessor {
// The Validator should be determinded based on the version of the service.
private Validator orderProcessValidator;
public Confirmation process(Order order) {
if(orderProcessValidator.validate(order)) {
// Business logic
}
}
}
Is possible to inject Validator dynamically with Spring IOC, or can only be solved through the factory pattern?
It is still a bit unclear for me your scenario, but I am assuming you have two actual Order classes in your project. Maybe one is in com.foo.api1 package and the other is in com.foo.api2 package. Or one Order is called Order1 and the other is called Order2. The idea is that I'm assuming you have two different classes for the two 'api versions' of Order.
You can achieve what you need by using Spring AOP:
#Aspect
#Component
public class MyAspect {
#Autowired
private Validator1 validator1;
#Autowired
private Validator2 validator2;
#Pointcut("execution(* com.foo.bar.OrderProcessor.process(..))")
private void myPointcut() {}
#Around("myPointcut() && args(order)")
public Object myAroundAdvice(ProceedingJoinPoint pjp, Object order) throws Throwable {
if (order instanceof Order1) {
validator1.validate((Order1) order);
} else
if (order instanceof Order2) {
validator2.validate((Order2) order);
}
Object retVal = pjp.proceed();
return retVal;
}
}
#Component
public class OrderProcessor {
public void process(Object order) {
System.out.println("processing order");
}
}
#Component
public class Validator1 {
public void validate(Order1 order) {
System.out.println("validating inside validator 1");
}
}
#Component
public class Validator2 {
public void validate(Order2 order) {
System.out.println("validating inside validator 2");
}
}
So, basically, you are defining an aspect that should intercept calls to your OrderProcessor class and, depending on what parameter it receives, it calls one validator or the other.

requestfactory complain about find method

I have a spring (3.1) application with a service and dao layer.
I try to use requestfactory (gwt 2.4) withi this spring layer.
Here some of my class
My domain class
public class Account {
Long id;
String username;
// get, set
}
The bridge between spring and gwt
public class SpringServiceLocator implements ServiceLocator {
#Override
public Object getInstance(Class<?> clazz) {
HttpServletRequest request = RequestFactoryServlet.getThreadLocalRequest();
ServletContext servletContext = request.getSession().getServletContext();
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);
return context.getBean(clazz);
}
}
My account proxy
#ProxyFor(value=Account.class, locator = AccountLocator.class)
public interface AccountProxy extends EntityProxy{
public Long getId();
public String getUsername();
public void setUsername(String userName);
public void setId(Long id);
}
RequestContext class
#Service(locator = SpringServiceLocator.class, value =AccountService.class)
public interface AccountRequest extends RequestContext {
Request<List<AccountProxy>> loadAllAccounts();
}
My requestFactory class
public interface AccountRequestFactory extends RequestFactory {
AccountRequest accountRequest();
}
My spring service
public interface AccountService {
public List<Account> loadAllAccounts();
}
#Service
public class AccountServiceImpl implements AccountService{
#Autowired
private AccountDAO accountDAO;
}
Account locator to avoid to put method in the entity
public class AccountLocator extends Locator<Account, Long> {
#Autowired
private AccountDAO accountDAO;
#Override
public Account create(Class<? extends Account> clazz) {
return new Account();
}
}
applicationContext.xml
<context:annotation-config />
<context:component-scan base-package="com.calibra" />
<bean id="accountService" class="org.calibra.server.service.AccountServiceImpl"/>
<bean id="accountDAO" class="org.calibra.server.dao.AccountDAOImpl"/>
The demo work but i get this error:
com.google.web.bindery.requestfactory.server.UnexpectedException: Could not find static method with a single parameter of a key type
Also on my AccountProxy i get this complain (a warning)
The domain type org.calibra.domain.Account has no Account findAccount(java.lang.Long) method. Attempting to send a AccountProxy to the server will result in a server error.
I don't want to add a find methond in my domain class.
I tried to put this method in my spring service, but i get the same warning.
Edit with the Locator that work fine
Just strange i need to put bean in the applicationContext, context:annotation and context:component-scan seem useless
Any idea?
The domain type org.calibra.domain.Account has no Account findAccount(java.lang.Long) method.
If you don't provide a find method of some kind, RequestFactory has no way of reconstituting objects when they get to the server - it can only create brand new ones, which prevents it from merging with existing data. Take this away, and you might as well have RPC again.
If you don't want static methods, provide a Locator instance which is able to find objects. From https://developers.google.com/web-toolkit/doc/latest/DevGuideRequestFactory#locators:
What if you don't want to implement persistence code in an entity itself? To implement the required entity locator methods, create an entity locator class that extends Locator:
public class EmployeeLocator extends Locator<Employee, Long> {
#Override
public Employee create(Class<? extends Employee> clazz)
{
return new Employee();
}
...
}
Then associate it with the entity in the #ProxyFor annotation:
#ProxyFor(value = Employee.class, locator = EmployeeLocator.class)
public interface EmployeeProxy extends EntityProxy {
...
}
You'll need to implement all of the methods, not just create - and the main one you are interested in is find(Class, Long). It may be possible to use one single Locator type for all proxies - as of 2.4.0 and 2.5.0-rc1 it is safe to fail to implement getDomainType(), and all of the other methods that need to know the exact type are provided with it as an argument.
Here is an example of what this can look like with JPA and Guice, but I think the idea is clear enough that it can be implemented with Spring and whatever persistence mechanism you are using. Here, all entities are expected to implement HasVersionAndId, allowing the locator to generalize on how to invoke getVersion and getId - you might have your own base class for all persisted entities.
(from https://github.com/niloc132/tvguide-sample-parent/blob/master/tvguide-client/src/main/java/com/acme/gwt/server/InjectingLocator.java)
public class InjectingLocator<T extends HasVersionAndId> extends Locator<T, Long> {
#Inject
Provider<EntityManager> data;
#Inject
Injector injector;
#Override
public T create(Class<? extends T> clazz) {
return injector.getInstance(clazz);
}
#Override
public T find(Class<? extends T> clazz, Long id) {
return data.get().find(clazz, id);
}
#Override
public Class<T> getDomainType() {
throw new UnsupportedOperationException();//unused
}
#Override
public Long getId(T domainObject) {
return domainObject.getId();
}
#Override
public Class<Long> getIdType() {
return Long.class;
}
#Override
public Object getVersion(T domainObject) {
return domainObject.getVersion();
}
}

Resources