I like SimpleMappingExceptionResolver, because in one place i have all exception->view mappings for all controllers in web-app (i suppose that). To customize some exception in specific controller i would like to use #ExceptionHandler, but it doesn't work together - all exceptions are handled by SimpleMappingExceptionResolver. How to make this work together ?
#Controller
public class SomeController {
...
#ExceptionHandler(SomeException.class)
public ModelAndView handleException(Exception ex) {
// ...
}
}
SimpleMappingExceptionResolver:
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="defaultErrorView" value="error"/>
<property name="exceptionMappings">
...
</property>
</bean>
Short answer: p:order
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver" p:order="1" />
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver" p:order="2" p:defaultErrorView="uncaughtException"/>
Full story: springsource forum.
Related
I have following configuration in application context
<jee:jndi-lookup id="dataSource" jndi-name="MY_DS" />
<context:load-time-weaver/>
<bean id="transactionManager" class="org.springframework.transaction.jta.WebLogicJtaTransactionManager" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean
class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="emf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jtaDataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="persistenceUnitName" value="pu_TEST" />
</bean>
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="database" value="ORACLE" />
<property name="showSql" value="true" />
</bean>
Now my DAO Class
#Repository
public class EmployeeDAO{
#PersistenceContext
private EntityManager em;
#Transactional
public void create(Employee entity) {
LOG.error("Enitity Manager:create" + em);
em.persist(entity);
// em.flush(); if i use flush it saves
}
}
Now when I save the entity it does not say give any error but no data is updated into db.
I do not wish to use flush as entitymanager is injected by spring and should perform flush at the end automatically which is not happening. correct my understanding.
Adding facade class may be issue is there, Does Propagation.REQUIRES_NEW has anything to do here?
#Transactional(propagation=Propagation.REQUIRES_NEW)
public void process(){
Employee e = factory.getEmployee();
employeeDao.create(e);
}
On Debug after create method call it shows employee got primary key populated that mean db call has made but at the end it is not persisted.
Please try either of the 3 :
1.Solution 1
Please call below code
em.joinTransaction();
just before
em.persistEntity(entity);
2.Solution 2
make attribute readOnly=false in #Transactional
3.Solution 3
Try manually adding bean EmployeeDAO in spring xml file
or else you can try below:
#Transactional(propagation=Propagation.REQUIRED)
I am trying to implement the following: I need to add two different entities in same same transaction to database.
I have different DAO classes and Service classes for each entity.
public class InvoicesDAO {
#Autowired
protected SessionFactory sessionFactory;
public void save(Invoice object) {
Session session = SessionFactoryUtils.getSession(sessionFactory, false);
session.persist(object);
}
}
public class RequestsDAO {
#Autowired
protected SessionFactory sessionFactory;
public void save(Request object) {
Session session = SessionFactoryUtils.getSession(sessionFactory, false);
session.persist(object);
}
}
public class InvoicesService {
#Autowired
private InvoicesDAO invoicesDAO;
#Autowired
private RequestsDAO requestsDAO;
#Transactional
public void add(Invoice object) throws HibernateException {
invoicesDAO.save(object);
}
#Transactional
public void updateAndGenerate(Invoice object1, Request object2) throws HibernateException {
invoicesDAO.save(object1);
requestsDAO.save(object2);
}
}
The config:
<tx:annotation-driven transaction-manager="transactionManager" />
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:/hibernate.properties" />
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${hibernate.connection.driver_class}" />
<property name="url" value="${hibernate.connection.url}" />
<property name="username" value="${hibernate.connection.username}" />
<property name="password" value="${hibernate.connection.password}" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.ejl.butler.object.data" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
<prop key="hibernate.cache.use_query_cache">${hibernate.cache.use_query_cache}</prop>
<prop key="hibernate.cache.region.factory_class">${hibernate.cache.region.factory_class}</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<context:annotation-config />
<context:component-scan base-package="com.service" />
<bean id="invoicesDao" class="com.dao.InvoicesDAO" />
<bean id="requestsDao" class="com.dao.RequestsDAO" />
Controller:
//***
/**
* Invoices access service
*/
#Autowired
private InvoicesService invoicesService;
// objects creation
invoicesService.updateAndGenerate(invoice, request);
//***
So when I am trying to call updateAndGenerate method and pass there invalid values for object2 - it fails without rolling back the object1. How can I fix it? Thank you
I dont think it is got to do with Proxies. You dont need a proxy object here. Generally you need a proxy object for instances such for a login service etc where you need a proxy object for the singleton bean definition. But, the only way it can not rollback is if your propogation level on the Transaction isnt correct.
If you use a Trasaction.REQUIRES_NEW then the dao.save wouldnt rollback and it wouldnt tie back to the outer transaction and hence wouldnt rollback.
Finally I figured out where the problem was so I will answer my own question...
According to Declarative transactions (#Transactional) doesn't work with #Repository in Spring and https://stackoverflow.com/a/3250959/705869 the order of the base-package items inside context:component-scan directive is very important. In additional, you should put only really necessary packages.
I had some duplicates inside this directive so the application context was initialized before database context. And that's why transactions were disabled inside services!
So check twice for base-package packages inside context:component-scan and remove unnecessary ones.
I have a problem with Spring MVC and REST. The problem is that when i post a url without extension or whatever extension other then json or html or htm i am always getting an xml response. But i want it to default to text/html response. I was searching in many topics and cant find the answear to this.
Here is my Controller class :
#RequestMapping(value="/user/{username}", method=RequestMethod.GET)
public String showUserDetails(#PathVariable String username, Model model){
model.addAttribute(userManager.getUser(username));
return "userDetails";
}
#RequestMapping(value = "/user/{username}", method = RequestMethod.GET,
produces={"application/xml", "application/json"})
#ResponseStatus(HttpStatus.OK)
public #ResponseBody
User getUser(#PathVariable String username) {
return userManager.getUser(username);
}
Here is my mvc context config:
<mvc:resources mapping="/resources/**"
location="/resources/"/>
<context:component-scan
base-package="com.chodak.controller" />
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="defaultContentType" value="text/html" />
<property name="mediaTypes">
<map>
<entry key="json" value="application/json"/>
<entry key="xml" value="application/xml"/>
</map>
</property>
</bean>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass">
<value>
org.springframework.web.servlet.view.tiles3.TilesView
</value>
</property>
</bean>
<bean id="tilesConfigurer"
class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/tiles.xml</value>
</list>
</property>
</bean>
Actually when I tried the built in Eclipse browser it works fine, but when I use firefox or chrome it shows xml response on a request with no extension. I tried using ignoreAcceptHeader, but no change.
Also works on IE :/
If anyone has an idea please help, Thank you.
I actually found out how to do it, i dont really understand why but it is working now, I added default views to the contentresolver like :
<property name="defaultViews">
<list>
<!-- JSON View -->
<bean
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
</bean>
<!-- JAXB XML View -->
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg>
<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.chodak.tx.model.User</value>
</list>
</property>
</bean>
</constructor-arg>
</bean>
</list>
</property>
and removed the getUser method, the one annoted to produce xml and json. If I leave it with the added default views its still not working. If anyone can explain why it would be awesome :)
You can do
import org.springframework.http.MediaType;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#Configuration
// #EnableWebMvc already autoconfigured by Spring Boot
public class MvcConfiguration {
#Bean
public WebMvcConfigurer contentNegotiationConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false)
.favorParameter(true)
.parameterName("mediaType")
.ignoreAcceptHeader(true)
.useJaf(false)
.defaultContentType(MediaType.APPLICATION_JSON)
.mediaType("xml", MediaType.APPLICATION_XML)
.mediaType("json", MediaType.APPLICATION_JSON);
// this line alone gave me xhtml for some reason
// configurer.defaultContentType(MediaType.APPLICATION_JSON_UTF8);
}
};
}
(tried with Spring Boot 1.5.x)
see https://spring.io/blog/2013/05/11/content-negotiation-using-spring-mvc
"What we did, in both cases:
Disabled path extension. Note that favor does not mean use one approach in preference to another, it just enables or disables it. The order of checking is always path extension, parameter, Accept header.
Enable the use of the URL parameter but instead of using the default parameter, format, we will use mediaType instead.
Ignore the Accept header completely. This is often the best approach if most of your clients are actually web-browsers (typically making REST calls via AJAX).
Don't use the JAF, instead specify the media type mappings manually - we only wish to support JSON and XML."
I am using <mvc:annotation-driven/> and I would like to configure RequestMappingHandlerMapping for disabling useTrailingSlashMatch. When I declare another RequestMappingHandlerMapping, I will end up 2 RequestMappingHandlerMapping. How can I configure RequestMappingHandlerMapping ?
As you have already noted, this is feasible in xml by removing mvc:annotation-driven and replacing with the entire xml equivalent:
<bean name="handlerAdapter" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="webBindingInitializer">
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="conversionService" ref="conversionService"></property>
<property name="validator">
<bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
</property>
</bean>
</property>
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"></bean>
</list>
</property>
</bean>
<bean name="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="useTrailingSlashMatch" value="true"></property>
</bean>
Can you try with Java config to override RequestMappingHandlerMapping value
#Configuration
#ComponentScan(basePackages = "base.package.name")
public class WebAppConfig extends WebMvcConfigurationSupport {
#Override
#Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping rmh = super.requestMappingHandlerMapping();
rmh.setUseTrailingSlashMatch(false);
return rmh;
}
}
If you want a solution that doesn't involve duplicating functionality in Spring then you can override the DisplatcherServlet. in Servlet 3.0 container this might look like:
#WebServlet(name="spring-dispatcher", loadOnStartup=1, urlPatterns={"/"},
initParams={
#WebInitParam(name="contextConfigLocation",
value="/WEB-INF/spring/spring-dispatcher-servlet.xml")})
public class MyDispatcherServlet extends DispatcherServlet {
#Override
protected void initStrategies(ApplicationContext context) {
super.initStrategies(context);
for (RequestMappingInfoHandlerMapping handlerMapping
: BeanFactoryUtils.beansOfTypeIncludingAncestors(
context, RequestMappingInfoHandlerMapping.class, true, false).values()) {
handlerMapping.setUseTrailingSlashMatch(false);
}
}
}
Add the following to your spring configuration file to toggle the useTrailingSlashMatch field.
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="useTrailingSlashMatch" value="true">
</property>
</bean>
We disable the quartz scheduler locally by commenting out the scheduler factory bean in the jobs.xml file.
Is there a setting for doing something similar in the quartz.properties file?
If you use Spring Framework you can make subclass from org.springframework.scheduling.quartz.SchedulerFactoryBean and override afterPropertiesSet() method.
public class MySchedulerFactoryBean extends org.springframework.scheduling.quartz.SchedulerFactoryBean {
#Autowired
private #Value("${enable.quartz.tasks}") boolean enableQuartzTasks;
#Override
public void afterPropertiesSet() throws Exception {
if (enableQuartzTasks) {
super.afterPropertiesSet();
}
}
}
Then change declaration of factory in xml file and set "enable.quartz.tasks" property in properties file. That's all.
Of course, instead using #Autowired you can write and use setter method and add
<property name="enableQuartzTasks" value="${enable.quartz.tasks}"/>
to MySchedulerFactoryBean declaration in xml.
No. But the properties file doesn't start the scheduler.
The scheduler doesn't start until/unless some code invokes scheduler.start().
It seems that there is a property autoStartup in org.springframework.scheduling.quartz.SchedulerFactoryBean. So you can configure it in XML config like this:
<bean id="quartzFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="autoStartup" value="${cron.enabled}"/>
<property name="triggers">
<list>
<ref bean="someTriggerName"/>
</list>
</property>
</bean>
Thanks to https://chrisrng.svbtle.com/configure-spring-to-turn-quartz-scheduler-onoff
You can disable Quartz Scheduler if you use Spring Framework 3.1 for creating and starting it.
On my Spring configuration file I use the new profiles feature of Spring 3.1 in this way:
<beans profile="production,test">
<bean name="bookingIndexerJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.xxx.indexer.scheduler.job.BookingIndexerJob" />
<property name="jobDataAsMap">
<map>
<entry key="timeout" value="10" />
</map>
</property>
</bean>
<bean id="indexerSchedulerTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="bookingIndexerJob" />
<property name="startDelay" value="1000" />
<property name="repeatInterval" value="5000" />
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="indexerSchedulerTrigger" />
</list>
</property>
<property name="dataSource" ref="ds_quartz-scheduler"></property>
<property name="configLocation" value="classpath:quartz.properties" />
<property name="applicationContextSchedulerContextKey" value="applicationContext" />
</bean>
</beans>
Only when I want to start the Scheduler (for example on the production environment), I set the spring.profiles.active system property, with the list of active profiles:
-Dspring.profiles.active="production"
More info here:
http://blog.springsource.com/2011/02/11/spring-framework-3-1-m1-released/
http://java.dzone.com/articles/spring-profiles-or-not
I personally like the answer from Demis Gallisto. If you can work with profiles, this would be my recommendation.
Nowadays people most likely prefer to work with Annotations, so as an addition to his answer.
#Configuration
#Profile({ "test", "prod" })
public class SchedulerConfig {
#Bean
// ... some beans to setup your scheduler
}
This will trigger the scheduler only when the profile test OR prod is active. So if you set an different profile, e.g. -Dspring.profiles.active=dev nothing will happen.
If for some reasons you cannot use the profile approach, e.g. overlap of profiles ...
The solution from miso.belica seems also to work.
Define a property. e.g. in application.properties: dailyRecalculationJob.cron.enabled=false and use it in your SchedulerConfig.
#Configuration
public class SchedulerConfig {
#Value("${dailyRecalculationJob.cron.enabled}")
private boolean dailyRecalculationJobCronEnabled;
#Bean
public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory, Trigger trigger) throws
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setAutoStartup(dailyRecalculationJobCronEnabled);
// ...
return factory;
}
// ... the rest of your beans to setup your scheduler
}
I had similar issue: disable scheduler in test scope.
Here is part of my applicationContext.xml
<task:annotation-driven scheduler="myScheduler" />
<task:scheduler id="myScheduler" pool-size="10" />
And I've disabled scheduler using 'primary' attribute and Mockito. Here is my applicationContext-test.xml
<bean id="myScheduler" class="org.mockito.Mockito" factory-method="mock" primary="true">
<constructor-arg value="org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler"/>
</bean>
Hope this help!
The simplest way I've found in a spring boot context for tests is to simply:
#MockBean
Scheduler scheduler;
This scala code works:
#Bean
def schedulerFactoryBean(): SchedulerFactoryBean = {
new SchedulerFactoryBean {
override def afterPropertiesSet(): Unit = {}
}
}