Managing transactions of dynamically created objects in spring - spring

I have a web service which receives a data object(Let's call the class Student). At the web service, I wrap it using a StudentWrapper object as follows
new StudentWrapper(student)
and I want the StudentWrapper class to have methods such as save which would save the data to the database. I want to use the spring framework to annotate the save method so that it will run within a transaction. But then the StudendWrapper object would have to be a spring bean(defined in XML). If it is a spring bean, then I won't be instantiating it as I have shown above.
My question is how can I make the StudentWrapper a Spring bean (so that I can use Spring annotations to manage the transactions) but pass the Student object (that I receive over the web service) in to the StudentWrapper?
If there are any other suggestions that would help me in solving this problem, please share them as well.

If you really want to create the object using a constructor, make the StudentWrapper #Configurable and read up about using AspectJ to create prototype bean definitions for domain objects (section 9.8 of the reference manual.)
A simpler alternative, if you don't want to go with AspectJ but don't want a direct dependency on Spring is to encapsulate the prototype bean creation in a factory. I'll show you using JavaConfig, though you can do something similar in XML.
First the student object...
package internal;
public class Student {
private String name;
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public String toString() {
return "Student{name='" + name + "'}";
}
}
And now the wrapper object...
package internal;
public class StudentWrapper {
private Student student;
public StudentWrapper(Student student) {
this.student = student;
}
public Student getStudent() {
return student;
}
#Override
public String toString() {
return "StudentWrapper{student='" + student + "'} " + super.toString();
}
}
And now the factory,
package internal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
#Component
public class StudentWrapperFactory {
#Autowired
private ApplicationContext applicationContext;
public StudentWrapper newStudentWrapper(Student student) {
return (StudentWrapper) this.applicationContext.getBean("studentWrapper", student);
}
}
And now the JavaConfig, equivalent to an XML configuration
package internal;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
#Configuration
#ComponentScan(basePackages = "internal")
public class FooConfig {
#Bean
#Scope("prototype")
public StudentWrapper studentWrapper(Student student) {
return new StudentWrapper(student);
}
}
Finally the unit test...
package internal;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {FooConfig.class})
public class FooIntegrationTest {
#Autowired
private StudentWrapperFactory studentWrapperFactory;
#Test
public void foo() {
Student student1 = new Student("student 1");
Student student2 = new Student("student 2");
StudentWrapper bean1 = this.studentWrapperFactory.newStudentWrapper(student1);
StudentWrapper bean2 = this.studentWrapperFactory.newStudentWrapper(student2);
System.out.println(bean1);
System.out.println(bean2);
}
}
produces
StudentWrapper{student='Student{name='student 1'}'} internal.StudentWrapper#1b0fa7ff
StudentWrapper{student='Student{name='student 2'}'} internal.StudentWrapper#20de643a
As you can see from the object references of StudentWrapper, they're different prototype beans. #Transactional methods should work as expected in StudentWrapper.

Related

How to implement the GET request using ServiceLocatorFactoryBean ( Factory Method design Pattern)

I thank you ahead for your time to read my request. I'm new to the Spring Service Locator Factory Method design Pattern and I don't understand the approach behind it. However I followed a turtorial and have been able to implement the Post request for my user registratio spring maven application. My src/main/java folder cointains this five packages:
Config
Controller
Model
Registry
Service
The Config package is to centralize the creation of users and its java class is as bellow:
package com.nidservices.yekoregistration.config;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.ServiceLocatorFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.nidservices.yekoregistration.registry.ServiceRegistry;
#Configuration
public class UserConfig {
#Bean
public FactoryBean<?> factoryBean() {
final ServiceLocatorFactoryBean bean = new ServiceLocatorFactoryBean();
bean.setServiceLocatorInterface(ServiceRegistry.class);
return bean;
}
}
The Registry package is to adapt the service base on the type of entity to create and is as bellow:
package com.nidservices.yekoregistration.registry;
public interface AdapterService<T> {
public void process(T request);
}
package com.nidservices.yekoregistration.registry;
public interface ServiceRegistry {
public <T> AdapterService<T> getService(String serviceName);
}
The Service package contains the different types of entity that inherit the User Model and the User Model is as bellow:
public class User implements Serializable {
private UUID id;
private String userIdentifier;
private String userType;
public String getUserIdentifier() {
return userIdentifier;
}
public void setUserIdentifier(String userIdentifier) {
this.userIdentifier = userIdentifier;
}
public String getUserType() {
return userType;
}
public void setUserType(String userType) {
this.userType = userType;
}
#Override
public String toString() {
return "User [userIdentifier=" + userIdentifier + ", UserType=" + userType + "]";
}
}
And the Post Request defined in the Controller is as bellow:
package com.nidservices.yekoregistration.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.nidservices.yekoregistration.model.User;
import com.nidservices.yekoregistration.registry.ServiceRegistry;
#RestController
#RequestMapping("/user")
public class UserController {
#Autowired
private ServiceRegistry serviceRegistry;
#PostMapping
public void processStudentDetails(#RequestBody User user) {
serviceRegistry.getService(user.getUserType()).process(user);
}
}
Now I'm struggling to make the GET Request to get all created users. I'm used with the DAO design pattern and very new with the concept behind ServiceLocatorFactoryBean. I appreciate your help to help me implement my CRUD endpoints using ServiceLocatorFactoryBean. Thanks in advance.

Using transactional in spring boot with hibernate

I am getting the error while using hibernate in spring boot application No qualifying bean of type TransactionManager' available
I am using the following config class:
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#org.springframework.context.annotation.Configuration
#EnableTransactionManagement
public class Config {
#Bean
public SessionFactory sessionFactory() {
Configuration configuration = new Configuration();
configuration.configure();
configuration.addAnnotatedClass(Ct.class);
configuration.addAnnotatedClass(St.class);
SessionFactory sessionFactory = configuration.buildSessionFactory();
return sessionFactory;
}
}
#RestController
public class RestAPIController {
#Autowired
private SessionFactory sessionFactory;
#PutMapping("/addS")
#Transactional
public void addSt(#RequestParam("cc") String cc,#RequestParam("st") String st) {
CC cc1= new CC();
CC.setCode(cc);
State state = new State(cc,st);
sessionFactory.getCurrentSession().save(state);
}
}
}
The main reason I added the #Transactional in the addSt method is due to error: The transaction was still an active when an exception occurred during Database.
So I turned to use spring boot for managing transactions. I am not sure what to do here.
--------------------UPDATED CODE--------------------
#Repository
public interface StateRepository extends CrudRepository<State, String> {}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.ArrayList;
import java.util.List;
#Service
#Transactional
public class StateService {
#Autowired
private StateRepository stateRepository;
public void save(State state) {
stateRepository.save(state);
}
public List<State> findAll() {
List<State> states = new ArrayList<>();
stateRepository.findAll().forEach(states::add);
return states;
}
}
For starters use proper layers and write a service and use JPA instead of plain Hibernate. If you want a Session you can always use EntityManager.unwrap to obtain the underlying Session.
#Service
#Transactional
public StateService {
#PersistenceContext
private EntityManager em;
public void save(State state) {
em.persist(state);
}
Use this service in your controller instead of the SessionFactory.
#RestController
public class RestAPIController {
private final StateService stateService;
RestAPIController(StateService stateService) {
this.stateService=stateService;
}
#PutMapping("/addS")
public void addSt(#RequestParam("cc") String cc, #RequestParam("st") String st) {
CC cc1= new CC();
CC.setCode(cc);
State state = new State(cc,st);
stateService.save(state);
}
}
Now ditch your Config class and restart the application.
NOTE
When using Spring Data JPA it is even easier, define a repository extending CrudRepository and inject that into the service instead of an EntityManager. (I'm assuming that Long is the type of primary key you defined).
public interface StateRepository extends CrudRepository<State, Long> {}
#Service
#Transactional
public StateService {
private final StateRepository states;
public StateService(StateRepository states) {
this.states=states;
}
public void save(State state) {
states.save(state);
}
}

How to us a constructor with parameters in a method used by Spring Boot's #RestController annotation to create a request handler

I bought this new book to try to learn Spring Boot quickly. It started out well, and I easily created a REST API. But then we added CrudRepository, and I'm seeing issues with the code as described in the book. Also, there is no code available to download because the author took it down from Oreily's git repo in order to fix some things...
The issue is that if I try to build the code as the book describes (without a default constructor) I get a Java error complaining that there is no default constructor. If I add a default constructor, it builds, but Spring uses it instead of the new constructor, that requires a parameter to be passed. So when I actually call the API, like if I call the /coffees endpoint, I get a java.lang.NullPointerException: null
So how is Spring supposed to know which constructor to use, and how could it pass in values for this parameter?
Here is the controller:
package com.bw.restdemo;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/coffees")
class RestAPIDemoController {
private final CoffeeRepository coffeeRepository;
public RestAPIDemoController(CoffeeRepository coffeeRepository) {
this.coffeeRepository = coffeeRepository;
this.coffeeRepository.saveAll(List.of(
new Coffee("Cafe Cereza"),
new Coffee("Freedom Fuel"),
new Coffee("Cold Brew"),
new Coffee("Sumatra")
));
}
public RestAPIDemoController() {
this.coffeeRepository = null;
};
//#RequestMapping(value = "/coffees", method = RequestMethod.GET)
#GetMapping
Iterable<Coffee> getCoffees() {
return coffeeRepository.findAll();
}
#GetMapping("/{id}")
Optional<Coffee> getCoffeeById(#PathVariable String id) {
return coffeeRepository.findById(id);
}
#PostMapping
Coffee postCoffee(#RequestBody Coffee coffee) {
return coffeeRepository.save(coffee);
}
#PutMapping("/{id}")
ResponseEntity<Coffee> putCoffee(#PathVariable String id, #RequestBody Coffee coffee) {
return (!coffeeRepository.existsById(id))
? new ResponseEntity<>(coffeeRepository.save(coffee), HttpStatus.CREATED)
: new ResponseEntity<>(coffeeRepository.save(coffee), HttpStatus.OK);
}
#DeleteMapping("/{id}")
void deleteCoffee(#PathVariable String id) {
coffeeRepository.deleteById(id);
}
}
Here is where I'm defining the interface:
package com.bw.restdemo;
import org.springframework.data.repository.CrudRepository;
interface CoffeeRepository extends CrudRepository<Coffee, String> {
}
And here's the main class -- apologies for the class stuffed at the bottom.
package com.bw.restdemo;
import java.util.UUID;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class RestDemoApplication {
public static void main(String[] args) {
SpringApplication.run(RestDemoApplication.class, args);
}
}
#Entity
class Coffee {
#Id
private String id;
private String name;
public Coffee(String id, String name) {
this.id = id;
this.name = name;
}
public void setId(String id) {
this.id = id;
}
public Coffee(String name) {
this(UUID.randomUUID().toString(), name);
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
CoffeeRepository interface is missing #Repository Annotation.
Update:
Add #Repository Annotation at CoffeeRepository
Remove the default constructor from RestAPIDemoController.
package com.bw.restdemo;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
interface CoffeeRepository extends CrudRepository<Coffee, String> {
}
Explanation
In spring framework, #Component annotation marks a java class as a bean so the component-scanning mechanism can pick it up and pull it into the application context. As #Repository serves as a specialization of #Component , it also enable annotated classes to be discovered and registered with application context.
More at HowToDoInJava - #Repository annotation in Spring Boot

Spring repository mvc how autowiring through interfaces and reaching specific repository implementations from a controller?

Good Morning,
I am building a web application and I chose to do it with an annotation driven spring mvc with REST Webservices (Jackson).
I am not using spring-boot because I wanted to add the libraries gradually when I needed them.
When I try to reach my specific repository with String str = ((GroupeMaterielRepository) repository).test(); i get a
java.lang.ClassCastException: com.sun.proxy.$Proxy210 cannot be cast
to pro.logikal.gestsoft.repository.GroupeMaterielRepository]
I would like to know how to access to my specific repository methods in which my HQL requests would be stored. I am trying to find a solution for days without success. The best I could do so far was accessing my CRUD methods in the generic repository implementation, but this implies to store in my repository interface every HQL method in the app, which will result as ugly.
I would like you to help me to get this code to work, keeping the logic of autowiring through interface's implementations extended by a more specific class with a controller layer and a repository layer.
Generic Controller :
package pro.logikal.gestsoft.controller;
import pro.logikal.gestsoft.repository.GenericCRUD;
public class GenericRestController<T> {
protected GenericCRUD<T> repository;
public GenericRestController(GenericCRUD<T> repository) {
this.repository = repository;
}
public GenericCRUD<T> getRepository() {
return repository;
}
}
Specific Controller :
package pro.logikal.gestsoft.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import pro.logikal.gestsoft.entity.GroupeMateriel;
import pro.logikal.gestsoft.repository.GenericCRUD;
import pro.logikal.gestsoft.repository.GroupeMaterielRepository;
#RestController
public class MaterielRESTController extends GenericRestController<GroupeMateriel> {
#Autowired
public MaterielRESTController(GenericCRUD<GroupeMateriel> repository) {
super(repository);
// TODO Auto-generated constructor stub
}
#GetMapping("/mat/groupes")
public ResponseEntity<String> getGroupes(){
String str = ((GroupeMaterielRepository) repository).test();
return new ResponseEntity<String>(str, HttpStatus.OK);
}
}
Repository Interface :
package pro.logikal.gestsoft.repository;
import java.util.List;
public interface GenericCRUD<T> {
void create(T entity);
void update(T entity);
void refresh(T entity);
void delete(Integer id);
T find (Integer id);
List<T> list();
}
Repository implementation :
package pro.logikal.gestsoft.repository;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.transaction.annotation.Transactional;
import pro.logikal.gestsoft.statics.ClientRequestUtils;
import pro.logikal.gestsoft.statics.DatabaseUtils;
#SuppressWarnings("unchecked")
#Transactional(DatabaseUtils.TM_GESTSOFT)
public class GenericCRUDImpl<T> implements GenericCRUD<T> {
#SuppressWarnings("unused")
public final Class<T> persistentClass;
#Autowired
#Qualifier(DatabaseUtils.GESTSOFT_SESSION)
public SessionFactory sessionFactory;
protected Session getCurrentSession() {
Session session = sessionFactory.getCurrentSession();
return session;
}
public GenericCRUDImpl(){
this.persistentClass= (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
#Override
public void create(final T entity) {
this.getCurrentSession().save(entity);
}
#Override
public void update(final T entity) {
this.getCurrentSession().update(entity);
}
#Override
public void refresh(final T entity) {
this.getCurrentSession().refresh(entity);
}
#Override
public void delete(Integer id) {
this.getCurrentSession().delete(this.find(id));
}
#Override
public T find(Integer id) {
// TODO Auto-generated method stub
return this.getCurrentSession().get(persistentClass, id);
}
#Override
public List<T> list() {
return this.getCurrentSession().createQuery("from "+persistentClass.getTypeName()).getResultList();
}
}
Repository associated to an entity and which is meant to contain the HQL requests for the related entities :
package pro.logikal.gestsoft.repository;
import org.springframework.stereotype.Repository;
import pro.logikal.gestsoft.entity.GroupeMateriel;
#Repository
public class GroupeMaterielRepository extends GenericCRUDImpl<GroupeMateriel> {
public String test() {
return "ok";
}
}
Just found out from where my problem came from reading [https://stackoverflow.com/a/6512431/8822802][1]
in my case #EnableAspectJAutoProxy(proxyTargetClass = true) on my config file

Using Mock class with dependency injection in a JUnit test

I have a basic Interface which another class is implementing.
package info;
import org.springframework.stereotype.Service;
public interface Student
{
public String getStudentID();
}
`
package info;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
#Service
public class StudentImpl implements Student
{
#Override
public String getStudentID()
{
return "Unimplemented";
}
}
I then have a service to inject that class into
package info;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
#Service
public class InfoService {
#Autowired
Student student;
public String runProg()
{
return student.getStudentID();
}
}
What I want to know is, how do I set up a JUnit test so that a Mock class of the Student interface steps in with a stubbed method instead of the method in StudentImpl. The injection does work but I want to use amock class to simulate the results instead for the sake of testing. Any help would be greatly appreciated.
In my opinion, autowiring in unit tests is a sign that's it's an integration test rather than unit test, so I prefer to do my own "wiring", as you describe. It might require you to do some refactoring of your code, but it shouldn't be a problem. In your case, I would add a constructor to InfoService that get's a Student implementation. If you wish, you can also make this constructor #Autowired, and remove the #Autowired from the student field. Spring would then still be able to autowire it, and it's also more testable.
#Service
public class InfoService {
Student student;
#Autowired
public InfoService(Student student) {
this.student = student;
}
}
Then it will be trivial to pass mocks between your services in your tests:
#Test
public void myTest() {
Student mockStudent = mock(Student.class);
InfoService service = new InfoService(mockStudent);
}

Resources