I'm working on a schema based multi-tenant app, in which I want to resolve the Tenant Identifier using a #RequestScope bean. My understanding is that #RequestScope uses/injects proxies for the request scoped beans, wherever they are referred (e.g. in other singleton beans). However, this is not working in the #Component that implements CurrentTenantIdentifierResolver and I get the following error when I start my service,
Caused by: org.springframework.beans.factory.support.ScopeNotActiveException: Error creating bean with name 'scopedTarget.userContext': Scope 'request' is not active for the current thread;
Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
Following are the relevant pieces of code.
#Component
public class CurrentTenant implements CurrentTenantIdentifierResolver {
#Autowired
private UserContext userContext;
#Override
public String resolveCurrentTenantIdentifier() {
return Optional.of(userContext)
.map(u -> u.getDomain())
.get();
}
#Component
#RequestScope
public class UserContext {
private UUID id;
private String domain;
My questions,
Isn't the proxy for the #RequestScope injected (by default)? Do I need to do anything more?
Is Hibernate/Spring trying to establish a connection to the DB at startup (even when there is no tenant available)?
Hibernate properties:
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
properties.remove(AvailableSettings.DEFAULT_SCHEMA);
properties.put(AvailableSettings.MULTI_TENANT, MultiTenancyStrategy.SCHEMA);
properties.put(AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER, tenantResolver);
properties.put(AvailableSettings.MULTI_TENANT_CONNECTION_PROVIDER, connectionProvider);
For the time being, I'm preventing the NullPointerException by checking if we are in the RequestContext. However, a connection still gets established to the master database (although I've explicitly specified the dialect and am not specifying hbm2ddl.auto). Since this connection is not associated with any schema, I'd like to avoid making it, so that it does not look for any tables that it won't find anyways.
What seems to be happenning is that when a HTTP request is received, hibernate is trying to resolve the current tenant identifier, even before my #RequestScope bean is created (and even before my #RestController method is called.) If a provide the default connection to the databse, I then get the following error. If I don't provide a connection, it throws an exception and aborts.
2021-09-26 11:55:44.882 WARN 19759 --- [nio-8082-exec-2] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 0, SQLState: 42P01
2021-09-26 11:55:44.882 ERROR 19759 --- [nio-8082-exec-2] o.h.engine.jdbc.spi.SqlExceptionHelper : ERROR: relation "employees" does not exist
Position: 301
2021-09-26 11:55:44.884 ERROR 19759 --- [nio-8082-exec-2] o.t.n.controller.EmployeeController : Exception: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
I am using Javers with Spring Hibernate JPA. The primary database is a MYSQL database with Javers connected to a seperate MongoDB server. I am not using Spring Data.
Everything works great with JaversAuditableAspect but I get the below errors when I use JaversAuditableAspectAsync.
I am using the default setup for the Async Javers.
#Bean
public JaversAuditableAspectAsync javersAuditableAspectAsync() {
return new JaversAuditableAspectAsync(javers(), authorProvider(), new EmptyPropertiesProvider(), javersAsyncAuditExecutor());
}
#Bean
public ExecutorService javersAsyncAuditExecutor() {
ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setNameFormat("JaversAuditableAsync-%d")
.build();
return Executors.newFixedThreadPool(2, threadFactory);
}
I understand this is an experimental feature but performance is very important in the area I intend to use Javers. Any advice on this would be greatly appreciated.
Errors upon first change attempt:
2020-07-29 10:54:35:497 [asdf#asdf.com E6DD9F] ERROR
DefaultRestExceptionHandler.defaultErrorHandler:120 - Error invoking '/service/form/save'. Exception: org.springframework.transaction.TransactionSystemException. Message: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction.
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction
Caused by: javax.persistence.RollbackException: Error while committing the transaction
Caused by: java.util.ConcurrentModificationException: null
Errors upon 2nd or more attempts:
2020-07-29 11:24:48:311 [asdf#asdf.com CD065A] ERROR DefaultRestExceptionHandler.defaultErrorHandler:120 - Error invoking '/service/form/save'. Exception: java.util.ConcurrentModificationException. Message: null.
java.util.ConcurrentModificationException: null
Stuck and have no clue why Spring Form is not able to submit successfully [gives binding issue] when pre-populated in get Request call loadForm, but works fine when populated in a method setupFormObject with #ModelAttribute annotation tag. I can provide a simple example in github to test out if asked for :)
Example below
#ModelAttribute("showForm")
public ShowForm setupFormObject() {
//Instantiate showForm with data
return showForm;
}
#RequestMapping(method = RequestMethod.GET)
public ModelAndView loadForm(#RequestParam("id") String id, HttpSession session) {
ModelAndView modelAndView = new ModelAndView(nextPage);
//Instantiate showForm with data
//modelAndView.addObject("showForm", showForm);
return modelAndView;
}
#RequestMapping(method = RequestMethod.POST)
public String post(#ModelAttribute("showForm") ShowForm showForm, BindingResult result, final RedirectAttributes redirectAttrs) {
//I see changed data here in showForm when populated using #setupFormObject
//See an exception in JSP with binding error if populated in loadForm
return "";
}
Stack Trace as requested. This exception is from github example.
`HTTP Status 500 - Request processing failed; nested exception is org.springframework.beans.InvalidPropertyException: Invalid property 'users[0]' of bean class [com.example.UserForm]: Illegal attempt to get property 'users' threw exception; nested exception is org.springframework.beans.NullValueInNestedPathException: Invalid property 'users' of bean class [com.example.UserForm]: Could not instantiate property type [com.example.UserEntity] to auto-grow nested property path: java.lang.InstantiationException: com.example.UserEntity`
`type Exception report`
`message Request processing failed; nested exception is org.springframework.beans.InvalidPropertyException: Invalid property 'users[0]' of bean class [com.example.UserForm]: Illegal attempt to get property 'users' threw exception; nested exception is org.springframework.beans.NullValueInNestedPathException: Invalid property 'users' of bean class [com.example.UserForm]: Could not instantiate property type [com.example.UserEntity] to auto-grow nested property path: java.lang.InstantiationException: com.example.UserEntity`
`description The server encountered an internal error that prevented it from fulfilling this request.`
`exception`
`org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.beans.InvalidPropertyException: Invalid property 'users[0]' of bean class [com.example.UserForm]: Illegal attempt to get property 'users' threw exception; nested exception is org.springframework.beans.NullValueInNestedPathException: Invalid property 'users' of bean class [com.example.UserForm]: Could not instantiate property type [com.example.UserEntity] to auto-grow nested property path: java.lang.InstantiationException: com.example.UserEntity`
`org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:927)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:822)
javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:796)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)`
`root cause`
`org.springframework.beans.InvalidPropertyException: Invalid property 'users[0]' of bean class [com.example.UserForm]: Illegal attempt to get property 'users' threw exception; nested exception is org.springframework.beans.NullValueInNestedPathException: Invalid property 'users' of bean class [com.example.UserForm]: Could not instantiate property type [com.example.UserEntity] to auto-grow nested property path: java.lang.InstantiationException: com.example.UserEntity
org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:829)
org.springframework.beans.BeanWrapperImpl.getNestedBeanWrapper(BeanWrapperImpl.java:556)
org.springframework.beans.BeanWrapperImpl.getBeanWrapperForPropertyPath(BeanWrapperImpl.java:533)
org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:894)
org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:75)
org.springframework.validation.DataBinder.applyPropertyValues(DataBinder.java:699)
org.springframework.validation.DataBinder.doBind(DataBinder.java:595)
org.springframework.web.bind.WebDataBinder.doBind(WebDataBinder.java:191)
org.springframework.web.bind.ServletRequestDataBinder.bind(ServletRequestDataBinder.java:112)
org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.bindRequestParameters(ServletModelAttributeMethodProcessor.java:153)
org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:106)
org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:77)
org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:162)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:123)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:746)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:687)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:915)
org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:822)
javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:796)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
`
Your help is highly appreciated
Thanks
The issue is actually that UserEntity does not have a default constructor, if you add the constructor it will work cleanly:
public UserEntity(){
//
}
I think what's happening is that the way your form is declared in the JSP, when submitting it it will assume that there is a UserEntity instance at position 0 in the users List of the UserForm instance, but it actually stumbles over a null reference.
Yes, you do add some UserEntity instances to the model when the form is displayed (using the loadForm method which is mapped to HTTP Get), but when you submit the form, a new model object is created, and this one will only have nulls in the users List.
Try making the model session scoped, this way the model instance you create when the form is shown will be reused when the form is submitted. Or create your own implementation of List that will return a new instance of UserEntity when a get(int position) is performed and there's nothing there.
When looking at my stack trace log, i have noticed that whenever i run any queries using the entity manager or EL (JPA 2.0) provided methods em.find(), findAll() ..., there is an Injected bean from all related entites that trigger n queries depending on the relationship. I have succesfully enabled weaving with tomcat using the spring.instruments jar and i am very sure that weaving is happening and my #OneToOne, #ManyToOne lazy settings are being set and woven in time. The problem might be how i query and the ServerSession connection that executes multiple queries.
The stack trace that shows this :
[EL Fine]: sql: 2012-07-04 22:26:20.959--ServerSession(1528617164)--Connection(1657707912)--Thread(Thread[tomcat-http--9,5,main])--SELECT personID, TYPE, DATEADDED, FIRSTNAME, LASTNAME, MIDDLENAME, ACTIVE, BIRTHDAY, EMAILADDRESS, ETHNICITY, GENDER, HISPANIC, IMAGEPATH, MARITAL, NATIVELANGUAGE, PRIMARYTELEPHONE, RELIGIOUSAFFILIATION, SECONDARYTELEPHONE, version, addressID, schoolID, MAJOR, studentId FROM PERSON WHERE (personID = ?)
bind => [101]
2012-07-04 22:26:20,963 [tomcat-http--9] DEBUG org.springframework.beans.factory.annotation.InjectionMetadata - Processing injected method of bean 'org.bixin.dugsi.domain.Administrator': PersistenceElement for transient javax.persistence.EntityManager org.bixin.dugsi.domain.Person.entityManager
2012-07-04 22:26:20,964 [tomcat-http--9] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'entityManagerFactory'
2012-07-04 22:26:20,964 [tomcat-http--9] DEBUG org.springframework.beans.factory.annotation.InjectionMetadata - Processing injected method of bean 'org.bixin.dugsi.domain.Administrator': PersistenceElement for transient javax.persistence.EntityManager org.bixin.dugsi.domain.Person.entityManager
2012-07-04 22:26:20,965 [tomcat-http--9] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'entityManagerFactory'
[EL Fine]: sql: 2012-07-04 22:26:20.966--ServerSession(1528617164)--Connection(264950364)--Thread(Thread[tomcat-http--9,5,main])--SELECT addressID, CITY, COUNTRY, STATE_US, STREETADDRESS, STREETADDRESS2, version, ZIPCODE FROM ADDRESS WHERE (addressID = ?)
bind => [3]
2012-07-04 22:26:20,970 [tomcat-http--9] DEBUG org.springframework.beans.factory.annotation.InjectionMetadata - Processing injected method of bean 'org.bixin.dugsi.domain.Address': PersistenceElement for transient javax.persistence.EntityManager org.bixin.dugsi.domain.Address.entityManager
2012-07-04 22:26:20,971 [tomcat-http--9] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'entityManagerFactory'
[EL Fine]: sql: 2012-07-04 22:26:20.972--ServerSession(1528617164)--Connection(255059556)--Thread(Thread[tomcat-http--9,5,main])--SELECT personID, TYPE, DATEADDED, FIRSTNAME, LASTNAME, MIDDLENAME, ACTIVE, BIRTHDAY, EMAILADDRESS, ETHNICITY, GENDER, HISPANIC, IMAGEPATH, MARITAL, NATIVELANGUAGE, PRIMARYTELEPHONE, RELIGIOUSAFFILIATION, SECONDARYTELEPHONE, version, addressID, schoolID, MAJOR, studentId FROM PERSON WHERE (addressID = ?)
bind => [3]
2012-07-04 22:26:20,975 [tomcat-http--9] DEBUG org.springframework.beans.factory.annotation.InjectionMetadata - Processing injected method of bean 'org.bixin.dugsi.domain.Student': PersistenceElement for transient javax.persistence.EntityManager org.bixin.dugsi.domain.Person.entityManager
2012-07-04 22:26:20,976 [tomcat-http--9] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'entityManagerFactory'
2012-07-04 22:26:20,976 [tomcat-http--9] DEBUG org.springframework.beans.factory.annotation.InjectionMetadata - Processing injected method of bean 'org.bixin.dugsi.domain.Student': PersistenceElement for transient javax.persistence.EntityManager org.bixin.dugsi.domain.Person.entityManager
2012-07-04 22:26:20,977 [tomcat-http--9] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'entityManagerFactory'
[EL Fine]: sql: 2012-07-04 22:26:20.98--ServerSession(1528617164)--Connection(2062869828)--Thread(Thread[tomcat-http--9,5,main])--SELECT schoolID, ACTIVE, ADMISSIONSEMAILADDRESS, ADMISSIONSPHONE, CODE, description, HELPGENERALEMAILADDRESS, NAME, PRIMARYPHONE, version, addressID FROM SCHOOL WHERE (schoolID = ?)
bind => [3]
2012-07-04 22:26:20,982 [tomcat-http--9] DEBUG org.springframework.beans.factory.annotation.InjectionMetadata - Processing injected method of bean 'org.bixin.dugsi.domain.School': PersistenceElement for transient javax.persistence.EntityManager org.bixin.dugsi.domain.School.entityManager
2012-07-04 22:26:20,982 [tomcat-http--9] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'entityManagerFactory'
[EL Fine]: sql: 2012-07-04 22:26:20.983--ServerSession(1528617164)--Connection(140234280)--Thread(Thread[tomcat-http--9,5,main])--SELECT id, ACTIVE, CODE, DESCRIPTION, NAME, version, SCHOOLDEPARTMENT_schoolID FROM DEPARTMENT WHERE (SCHOOLDEPARTMENT_schoolID = ?)
bind => [3]
[EL Fine]: sql: 2012-07-04 22:26:20.986--ServerSession(1528617164)--Connection(1812702959)--Thread(Thread[tomcat-http--9,5,main])--SELECT personID, TYPE, DATEADDED, FIRSTNAME, LASTNAME, MIDDLENAME, ACTIVE, BIRTHDAY, EMAILADDRESS, ETHNICITY, GENDER, HISPANIC, IMAGEPATH, MARITAL, NATIVELANGUAGE, PRIMARYTELEPHONE, RELIGIOUSAFFILIATION, SECONDARYTELEPHONE, version, addressID, schoolID, MAJOR, studentId FROM PERSON WHERE (schoolID = ?)
bind => [3]
How to ignore cache and return right away after executing a query on an entity manager object?
#RooJavaBean
#RooToString
#RooJpaActiveRecord(identifierColumn = "addressID")
public class Address {
#Id
#TableGenerator(name = "ADDRESS_TABLE_GEN", table = "ADDRESS_SEQUENCE_TABLE", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "ADDR_SEQ", allocationSize = 1, initialValue = 1)
#GeneratedValue(strategy = GenerationType.TABLE, generator = "ADDRESS_TABLE_GEN")
#Column(name = "addressID")
private Long id;
#BatchFetch(BatchFetchType.JOIN)
#OneToMany(cascade = CascadeType.ALL, mappedBy = "address", fetch = FetchType.EAGER)
private Set<Person> persons = new HashSet<Person>();
Applicant entity
public class Applicant extends Person {
private String major;
#BatchFetch(BatchFetchType.JOIN)
#OneToMany(targetEntity = ApplicantSchool.class, cascade = { javax.persistence.CascadeType.PERSIST, javax.persistence.CascadeType.REMOVE }, mappedBy = "applicant", fetch = FetchType.EAGER)
private Set<ApplicantSchool> schools = new HashSet<ApplicantSchool>();
}
Stack Trace; Reverting a particular OneToOne mapping
[TomcatInstrumentableClassLoader#747917a] error aspect 'org.springframework.orm.jpa.aspectj.JpaExceptionTranslatorAspect' woven into 'org.bixin.dugsi.domain.Registration_Roo_Jpa_ActiveRecord' must be defined to the weaver (placed on the aspectpath, or defined in an aop.xml file if using LTW).
[TomcatInstrumentableClassLoader#747917a] error aspect 'org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl' woven into 'org.bixin.dugsi.domain.Registration_Roo_Jpa_ActiveRecord' must be defined to the weaver (placed on the aspectpath, or defined in an aop.xml file if using LTW).
2012-07-06 17:08:34,910 ["http-bio-8080"-exec-1] DEBUG org.springframework.beans.factory.annotation.InjectionMetadata - Found injected element on class [org.bixin.dugsi.domain.Registration]: PersistenceElement for transient javax.persistence.EntityManager org.bixin.dugsi.domain.Registration.entityManager
2012-07-06 17:08:34,910 ["http-bio-8080"-exec-1] DEBUG org.springframework.beans.factory.annotation.InjectionMetadata - Processing injected method of bean 'org.bixin.dugsi.domain.Registration': PersistenceElement for transient javax.persistence.EntityManager org.bixin.dugsi.domain.Registration.entityManager
2012-07-06 17:08:34,911 ["http-bio-8080"-exec-1] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'entityManagerFactory'
2012-07-06 17:08:34,914 ["http-bio-8080"-exec-1] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor#0'
[EL Warning]: metadata: 2012-07-06 17:08:34.968--ServerSession(1433743869)--Thread(Thread["http-bio-8080"-exec-1,5,main])--Reverting the lazy setting on the OneToOne or ManyToOne attribute [person] for the entity class [class org.bixin.dugsi.domain.UserAccount] since weaving was not enabled or did not occur.
This is the field EL is referring to
#OneToOne(targetEntity = Person.class, fetch = FetchType.LAZY)
#JoinColumn
private Person person;
You are specifying FetchType.EAGER in both the relationships you've shown, so they must always be fetched when building the source objects. As mentioned, the problem seems to be reading in Person (or Applicant) which causes Address to be fetched. Chances are that the 'address' ManyToOne in Person is also marked eager. This causes Addresses to be built, and because you have a 1:M from Address->Applicant, this query must go to the database to make sure that it fetched all Applicants.
This same senario happens on all the referenced eagerly fetched entities, and is why it is a bad idea to have everything marked eager unless it is neccessary, especially OneToMany and ManyToMany relationships. I'd recommend you change them to lazy and only fetch them as required when the relationship is accessed, or use fetch join in queries or query hints to prefetch particular relationships that will be needed.