I want to use container managed transaction in one class and share it with its subclasses.
Here is my abstract class :
#TransactionManagement(TransactionManagementType.CONTAINER)
public abstract class AbstractDAO {
#PersistenceContext(unitName = "myDS")
protected EntityManager em;
#Resource
protected SessionContext context;
protected Logger log;
public AbstractDAO() {
log = LoggerFactory.getLogger(this.getClass());
}
}
One of its child :
#Stateless
#TransactionManagement(TransactionManagementType.CONTAINER)
public class OrdreDAO extends AbstractDAO {
public OrdreDAO() {
}
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void persist(Ordre o) {
em.persist(o);// NPE here ... no EntityManager injected !
}
#SuppressWarnings("unchecked")
public List<Ordre> findAll() {
Query q = em.createQuery("from Ordre");
return q.getResultList();
}
}
On top of this child , OrdreService :
public class OrdreService {
private OrdreDAO dao;
public OrdreService() {
dao=new OrdreDAO();
}
public void persist(Ordre o) {
System.out.println("Service::persist ??");
dao.persist(o);
}
public List<Ordre> getOrdres() {
return dao.findAll();
}
public Ordre getOrdre(String id) {
return dao.findByPK(id);
}
public Ordre merge(Ordre o) {
return dao.merge(o);
}
}
A servlet using it :
public class creerOrdre extends HttpServlet {
private static final long serialVersionUID = 1L;
private OrdreService os;
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
try {
System.out.println("création ordre");
Ordre o = new Ordre();
o.setDate(req.getParameter("date"));
o.setMotif(req.getParameter("motif"));
System.out.println("Ordre: " + o.getDate() + " " + o.getMotif());
OrdreService os = new OrdreService()
if (os!=null) {
System.out.println("NON null !");
}
os.persist(o);
resp.sendRedirect("visualiser.jsp");
} catch (ParseException pe) {
throw new ServletException(pe);
}
}
}
I get a NPE when I try to persist an Ordre
What am I missing ?
JDK 6
JBoss 5.1.0.GA
JPA 1
Your OrdreService POJO class is not managed by the web container, and also it seems to me that it's a useless additional layer. I would use only the OrdreDAO.
Anyway if you want to keep both classes, make OrdreService a Stateless EJB. Inject in OrdreService the OrdreDAO instance using:
#EJB private OrdreDAO dao;
Finally, inject OrdreService in your servlet using:
#EJB private OrdreService os;
This should work.
Related
Environment:
JBoss 7.2
Java 11
I am trying to insert data to a DB from a JSF page through TestBean controller, but I am getting an error saying javax.persistence.TransactionRequiredException that I need a transaction.
The insert method() is in a #Stateless ConsultaService, so I thought that it was by default transactional but it looks like something is wront.
This code is being migrated from JBoss 5.2 but I had no problem, when I invoked insert method() a transaction was created without any problem. Has that changed in JBoss 7.2?
Should I add #Transactional to every method? or there is something else that I am missing?
**TestBean.java **
#Named
#ViewScoped
public class TestBean implements Serializable {
...
#Inject
ConsultaServiceable consultaSvc;
...
public void insert() {
try {
Consulta consulta1 = new Consulta();
consulta1.setConsulta("hola");
consulta1.setCognom1("cognom");
consulta1.setCp("07000");
consulta1.trace();
consultaSvc.insert(consulta);//ERROR TransactionRequiredException
} catch (AppException e) {
log.error("error inserting consulta", e);
}
}
...
}
BusinessServiceable.java
public interface BusinessServiceable<T> extends QueryServiceable<T> {
T insert(T entity) throws AppException;
T update(T entity) throws AppException;
void remove(T entity) throws AppException;
}
QueryService.java
public abstract class QueryService<T> extends Queryable implements QueryServiceable<T> {
#PersistenceContext(unitName = "bdPU")
protected EntityManager eManager;
protected Class<T> entityClass;
...
public QueryService(Class<T> entityClass) {
this.entityClass = entityClass;
}
...
}
BusinessService.java
public abstract class BusinessService<T> extends QueryService<T> implements BusinessServiceable<T> {
...
#PermitAll
public T insert(T entity) throws AppException {
try {
eManager.persist(entity);
} catch (Exception e) {
log.error("Error on BusinessService.insert ", e);
Throwable t = e.getCause();
if (t instanceof org.hibernate.exception.ConstraintViolationException) {
throw new AppException("Error on BusinessService.insert " + entity.getClass().getSimpleName() + " id " + entity.toString(), e);
} else {
throw new AppException("Error on insert", e);
}
}
return entity;
}
...
}
ConsultaService.java
#Stateless
#Local
#PermitAll
public class ConsultaService extends BusinessService<Consulta> implements ConsultaServiceable {
public ConsultaService() {
super(Consulta.class);
}
#PermitAll
#Override
public Consulta insert(Consulta entity) throws AppException {
return super.insert(entity);
}
...
}
Error server log
10:46:52,329 ERROR [es.caib.accfor.business.QueryService] (default task-1) Error on BusinessService.insert : javax.persistence.TransactionRequiredException: WFLYJPA0060: Transaction is required to perform this operation (either use a transaction or extended persistence context)
at org.jboss.as.jpa#7.2.0.GA-redhat-00005//org.jboss.as.jpa.container.AbstractEntityManager.transactionIsRequired(AbstractEntityManager.java:877)
at org.jboss.as.jpa#7.2.0.GA-redhat-00005//org.jboss.as.jpa.container.AbstractEntityManager.persist(AbstractEntityManager.java:579)
at deployment.accfor2.ear//es.caib.accfor.business.BusinessService.insert(BusinessService.java:43)
at deployment.accfor2.ear//es.caib.accfor.business.consulta.boundary.ConsultaService.insert(ConsultaService.java:46)
at deployment.accfor2.ear//es.caib.accfor.business.consulta.boundary.ConsultaService$Proxy$_$$_WeldSubclass.insert(Unknown Source)
at deployment.accfor2.ear//es.caib.accfor.business.consulta.boundary.ConsultaService.insert(ConsultaService.java:14)
at deployment.accfor2.ear.accfor-front.war//es.caib.accfor.presentation.front.TestBean.insert(TestBean.java:57)
It was a problem wih pom.xml dependencies and ejb module.
how can i inject EntityManager(jpa) with Mockito?
I wanna bind Mockito.spy(UserService.class) to guice injector.
but UserService.class has EntityManager for query execution.
When installing 'JunitServiceModule' in guice injector, EntityManager is not found.
See below for error details
com.google.inject.CreationException: Unable to create injector, see the following errors:
1) Error in custom provider, java.lang.NullPointerException
while locating com.google.inject.persist.jpa.JpaPersistService
while locating javax.persistence.EntityManager
My code is below.
(The test code just made the error situation similar.)
(actually 'EntityManager' is located in UserRepository... It's just example!)
(#Transactional is belong to guice)
public class UserServiceTest {
#Inject
private UserService userService;
#Before
public void setUp() {
Injector injector = new TestBuilder().init();
injector.initMembers(this);
Mockito.doReturn(10).when(userService).getEntityCount(UserEntity.class);
}
#Test
public void test() {
assertEquals(10, userService.getEntityCount(UserEntity.class));
}
}
public class TestBuilder {
public TestBuilder() {
}
public Injector init() {
Injector injector = Guice.createInjector(
new TestDBInjectModule("test"),
new JunitServiceModule()
);
}
}
public class TestDBInjectModule extends AbstractModule {
private String unitName;
public TestDBInjectModule(String unitName) {
this.unitName = unitName;
}
#Override
protected void configure() {
install(new JpaPersistModule(unitName));
bind(JpaInitializer.class).asEagerSingleton();
}
#Singleton
private static class JpaInitializer {
#Inject
public JpaInitializer(final PersistService persistService) {
persistService.start();
}
}
}
public class JunitServiceModule extends AbstractModule {
#Override
protected void configure() {
bind(UserService.class).toInstance(Mockito.spy(UserService.class));
}
}
public class UserService {
#Inject
private EntityManager entityManager;
public UserService {} // <-- throw NullPointerException!!! since EntityManager
#Transactional
public void addUser(User user) {
return entityManager.persist(user);
}
public Number getCount() {
return entityManager.createQuery("select count(*) from user", Number.class).getSingleResult();
}
}
My Spring Boot application implements the TenantStore example for storing data in ThreadLocalTargetSource detailed in this link
#Bean(destroyMethod = "destroy")
public ThreadLocalTargetSource threadLocalTenantStore() {
ThreadLocalTargetSource result = new ThreadLocalTargetSource();
result.setTargetBeanName("tenantStore");
return result;
}
The working example allows for the TenantStore object to be set and injected by the Spring Framework. My version of the TenantFilter class described in that article sets the properties of the TenantStore object whenever a Servlet request is made
#Autowired
private TenantStore tenantStore;
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
try {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null) {
String token = (String) request.getAttribute(ACCESS_TOKEN_VALUE);
if (token != null) {
OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(token);
if (oAuth2AccessToken.getAdditionalInformation() != null) {
String tenantName = (String) oAuth2AccessToken.getAdditionalInformation().get("tenant");
storeTenantInThread(tenantName);
}
}
}
chain.doFilter(request, response);
} catch (ResourceNotFoundException e) {
log.error(e.getMessage());
} finally {
clearTenant();
}
}
private void storeTenantInThread(String tenantName) {
tenantStore.setName(tenantName);
}
private void clearTenant() {
tenantStore.clear();
}
I then have a number of services where TenantStore is autowired and in each of these services the TenantStore contains the information that was populated in the doFilter() method. Except for one class. For some reason the properties of the TenantStore in this class are still null. The name of the class affected is MyCacheService and the architecture is as follows:
#RestController
#RequestMapping("/here")
public class MyController {
#Autowired
private MyService myService
#GetMapping
public ResponseEntity myGetMethod(#RequestParam("text") String text) {
myService.myMethod(text);
return new ResponseEntity(Http.OK);
}
}
#Service
public class MyService {
#Autowired
private TenantStore tenantStore;
#Autowired
private MyOtherService myOtherService;
public void myMethod(String text) {
System.out.println(tenantStore.getName()); //works - prints name
myOtherService.myOtherMethod(text);
}
}
#Service
public class MyOtherService {
#Autowired
private TenantStore tenantStore;
#Autowired
private Map<String, MyComponent> myComponents;
public void myOtherMethod(String text) {
System.out.println(tenantStore.getName()); //works - prints name
MyComponent useThisComponent = myComponents.get("componentName");
useThisComponent.myComponentMethod(text);
}
}
#Component("componentName")
public class MyComponent {
#Autowired
private TenantStore tenantStore;
#Autowired
private MyCacheService myCacheService;
public void myComponentMethod(String text) {
System.out.println(tenantStore.getName()); //works - prints name
entityAliasCacheService.myCacheMethod(String text);
}
}
#Service
public class MyCacheService {
#Autowired
private TenantStore tenantStore;
public void myCacheMethod(String text) {
System.out.println(tenantStore.getName()); //DOES NOT WORK - tenantStore object is not null but the name property is
}
}
From what I can guess, for some reason the TenantStore in MyCacheService is being populated in a different thread, though I've no idea why.
I noticed similar behaviour. I fixed the issue by adding a bean dependancy
#Service
#DependsOn("proxiedThreadLocalTargetSource") // asks Spring to first load proxy bean
public class MyCacheService {
where proxiedThreadLocalTargetSource bean is defined like in the OP's example -
#Primary
#Bean(name = "proxiedThreadLocalTargetSource")
public ProxyFactoryBean proxiedThreadLocalTargetSource(ThreadLocalTargetSource threadLocalTargetSource) {
ProxyFactoryBean result = new ProxyFactoryBean();
result.setTargetSource(threadLocalTargetSource);
return result;
}
So, by adding the dependancy, Spring knows that it should load MyCacheService bean after the proxiedThreadLocalTargetSource. Without this dependancy, I noticed that TenantStore got injected instead of the proxy bean.
Getting instance of TenantStore from org.springframework.context.ApplicationContext
First implement ApplicationContextAware like as below
#Component
public class ApplicationContextUtil implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static ApplicationContext context() {
return context;
}
}
And your MyCacheService Will be like this:
public class MyCacheService {
public void myCacheMethod(String text) {
TenantStore tenantStore = ApplicationContextUtil.context().getBean(TenantStore.class);
System.out.println(tenantStore.getName());
}
}
I have the following service layout of nested transactions:
#Component
public class Main implements RPCInterface {
#Autowired
private ServiceA serviceA;
#Autowired
private ServiceB serviceB;
#Autowired
private ServiceC serviceC;
#Override
#Transactional (value="txManager", propagation=Propagation.REQUIRED, rollbackFor={ExceptionOne.class, ExceptionTwo.class, ExceptionThree.class})
public void outerMethod() throws ExceptionO {
try {
serviceA.methodA();
serviceB.methodB();
serviceC.methodC();
} catch (ExceptionOne e) {
throw new ExceptionO(e.getMessage, e);
} catch (ExceptionTwo e) {
throw new ExceptionO(e.getMessage, e);
} catch (ExceptionThree e) {
throw new ExceptionO(e.getMessage, e);
}
}
}
#Service
public class ServiceA implements SA {
#Autowired
private ServiceA1 serviceA1;
#Override
public void methodA() {
serviceA1.methodA1();
}
}
#Service
public class ServiceA1 implements SA1 {
#Autowired
private ServiceDBTable1 serviceDBTable1;
#Autowired
private ServiceA1A serviceA1A;
#Transactional
#Override
public void methodA1() {
serviceDBTable4.callToMapper4();
serviceA1A.methodA1A();
}
}
#Service
#Transactional (value="txManager", propagation=Propagation.REQUIRED)
public class ServiceA1A implements SA1A {
#Autowired
private ServiceDBTable2 serviceDBTable2;
#Override
public void methodA1A() {
serviceDBTable1.callToMapper1();
}
}
#Service
public class ServiceB implements SB {
#Autowired
private ServiceDBTable3 serviceDBTable3;
#Override
#Transactional (value="txManager", propagation=Propagation.REQUIRED)
public void methodB() {
serviceDBTable3.callToMapper3();
}
}
#Service
public class ServiceC implements SC {
#Override
public void methodC() throws ExceptionThree {
// code that throws ExceptionThree
}
}
I need to make all the DB calls within ServiceA and ServiceB nested calls to rollback when ServiceC#methodC() throws an exception (or any of them for that matter that throws an exception -- ServiceA or ServiceB).
I tried to make Main#outerMethod transactional with REQUIRED propagation, but it seems like the database commits are not being rolled back. I have even specified the specific classes with rollbackFor but the commits persist. Does anyone know how to fix this issue?
What I did to make it work was to migrate ServiceB.methodB() and ServiceC.methodC() calls to ServiceA.methodA(), and make methodA() #Transactional while throwing all my exceptions from methodA() and rollback based on those three exceptions (my logic actually allowed me to do that):
#Component
public class Main implements RPCInterface {
#Autowired
private ServiceA serviceA;
#Override
public void outerMethod() throws ExceptionO {
try {
serviceA.methodA();
} catch (ExceptionOne e) {
throw new ExceptionO(e.getMessage, e);
} catch (ExceptionTwo e) {
throw new ExceptionO(e.getMessage, e);
} catch (ExceptionThree e) {
throw new ExceptionO(e.getMessage, e);
}
}
}
#Service
public class ServiceA implements SA {
#Autowired
private ServiceA1 serviceA1;
#Autowired
private ServiceB serviceB;
#Autowired
private ServiceC serviceC;
#Override
#Transactional (value="txManager", propagation=Propagation.REQUIRED, rollbackFor={ExceptionOne.class, ExceptionTwo.class, ExceptionThree.class})
public void methodA() throw ExceptionOne, ExceptionTwo, ExceptionThree {
serviceA1.methodA1();
serviceB.methodB();
serviceC.methodC();
}
}
#Service
public class ServiceA1 implements SA1 {
#Autowired
private ServiceDBTable1 serviceDBTable1;
#Autowired
private ServiceA1A serviceA1A;
#Transactional
#Override
public void methodA1() {
serviceDBTable4.callToMapper4();
serviceA1A.methodA1A();
}
}
#Service
#Transactional (value="txManager", propagation=Propagation.REQUIRED)
public class ServiceA1A implements SA1A {
#Autowired
private ServiceDBTable2 serviceDBTable2;
#Override
public void methodA1A() {
serviceDBTable1.callToMapper1();
}
}
#Service
public class ServiceB implements SB {
#Autowired
private ServiceDBTable3 serviceDBTable3;
#Override
#Transactional (value="txManager", propagation=Propagation.REQUIRED)
public void methodB() {
serviceDBTable3.callToMapper3();
}
}
#Service
public class ServiceC implements SC {
#Override
public void methodC() throws ExceptionThree {
// code that throws ExceptionThree
}
}
Since there is no code presented it is hard to know for sure.
However, transactions only work when methods are public. Private methods are not proxied and hence transaction support for them is not there.
Read through Declarative Transations - Spring Docs for more details.
Please post code if you still are struggling for getting better help.
Here is My Servlet
#WebServlet("/UserServlet")
public class UserServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
#Inject IUserBusiness userBusiness;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
List<UserBean> usersList=new ArrayList<UserBean>();
usersList=userBusiness.getAllUsers();
usersList.size();
}
And I have next interface and implementations
public interface IUserBusiness {
List<UserBean> getAllUsers();
}
public class UserBusiness implements IUserBusiness{
public List<UserBean>userList;
public UserBusiness() {
userList=new ArrayList<UserBean>();
}
public List<UserBean> getAllUsers(){
UserBean user=new UserBean();
user.setAge(44);
user.setEmail("fgdfg");
user.setPassword("dfgdfgf");
userList.add(user);
return this.userList;
}
}
And then I configure the injector like this
public class Listener extends GuiceServletContextListener {
#Override
protected com.google.inject.Injector getInjector() {
return Guice.createInjector(
new ServletModule() {
#Override protected void configureServlets() {
serve("/index.html").with(UserServlet.class);
}
},
new Configure());
}
and
public class Configure extends com.google.inject.AbstractModule{
#Override
protected void configure() {
bind(IUserBusiness.class).to(UserBusiness.class);
}
}
But I get a 500 error (nullPointer Exception at userBusiness in servlet)
Servlet.service() for servlet [dynamic.UserServlet] in context with path [/dynamic] threw exception
java.lang.NullPointerException
at dynamic.UserServlet.doGet(UserServlet.java:36)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
If you're using Guice, why do you have #WebServlet("/UserServlet") set? An extra annotation won't do any harm, except that it may mask a separate misconfiguration.
Make sure you're accessing the servlet through your Guice bindings, because if you're accessing it through some other configuration, your #Inject fields will not be set and you'll get an NPE when trying to access them.