Equivalent of mvc:default-servlet-handler in Spring annotation-based configuration? - java

Is it possible to have the equivalent of <mvc:default-servlet-handler/> defined in an AnnotationConfig(Web)ApplicationContext? Right now I have:
#Configuration
#ImportResource("classpath:/mvc-resources.xml")
class AppConfig {
// Other configuration...
}
with just the following in my resources/mvc-resources.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<mvc:default-servlet-handler/>
</beans>
And it works as expected. Is it possible to do this without importing an XML file? It would be a nice way to cut down on some boilerplate.

If you are using Spring 3.1 with WebMvc, you can configure default servlet handling like this:
#Configuration
#EnableWebMvc
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}

After digging a bit deeper, I found out that this is a known problem and is addressed by annotation features in the upcoming Spring 3.1.
I solved my problem with the following code:
#Configuration
#Import(FeatureConfig.class)
class AppConfig {
...
}
#FeatureConfiguration
class FeatureConfig {
#Feature
public MvcDefaultServletHandler defaultHandler() {
return new MvcDefaultServletHandler();
}
}
This does require using the milestone version of spring, though, but it seems to be the cleanest and preferred way of handling this.

I don't think you can do it out of the box, but you can probably copy what DefaultServletHandlerBeanDefinitionParser does: Create a Bean of type DefaultServletHttpRequestHandler and map it to the URL scheme /**.
I'd say your Bean should subclass DefaultServletHttpRequestHandler and do the mapping in a #PostConstruct method.

#Bean
public DefaultServletHttpRequestHandler defaultServletHttpRequestHandler() {
return new DefaultServletHttpRequestHandler();
}
#Bean
public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
Map<String, String> urlMap = new ManagedMap<String, String>();
urlMap.put("/**", defaultServletHandlerName);
SimpleUrlHandlerMapping hm = new SimpleUrlHandlerMapping();
hm.setUrlMap(urlMap);
return hm;
}

Related

CDI injection with ExceptionMapper- #inject null

I have the following ExceptionMapper:
#Provider
public class GenericExceptionMapper
implements ExceptionMapper<Exception> {
#Inject
private ExceptionDAO exceptionDAO;
#Override
public Response toResponse(Exception e) {
LOGGER.error(e.getMessage(), e);
return Response.status(INTERNAL_SERVER_ERROR)
.type(MediaType.TEXT_PLAIN)
.entity(e.getMessage())
.build();
}
The exceptionDAO is always null. I have a beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee /beans_1_0.xsd"
></beans>
I have tried injecting alot of classes, but they always show as null.
Both the class being managed (ExceptionDAO) and the class injecting it need to be CDI-aware. In this case, this will probably involve marking both classes with #RequestScoped (or other CDI normal scope).
Do not get rid of the #Provider or other JAX-RS annotations; just add the CDI annotation.

SpringMVC Jackson2HttpMessageConverter customization doesn't work

I want to use custom JsonSerializer for JSON response of SpringMVC4.
In order to add JsonSerializer, I created WebMvcConfigurerAdapter subclass.
But customization of MappingJackson2HttpMessageConverter didn't work.
Simplify the problem, I tried setJsonPrefix.
But it also didn't work. The response didn't changed.
My code is below. Please tell me what is wrong.
ControllerClass
#Controller
public class SampleController {
#RequestMapping("/sample")
#ResponseBody
public ResponseModel action() {
return new ResponseModel();
}
public static class ResponseModel {
public String id = "001";
public String text = "aaa";
}
}
Configuration
#Configuration
#EnableWebMvc
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(converter());
super.configureMessageConverters(converters);
}
#Bean
protected MappingJackson2HttpMessageConverter converter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setJsonPrefix("prefix");
return converter;
}
}
dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
xmlns:aop="http://www.springframework.org/schema/aop">
<!-- base package -->
<context:annotation-config />
<context:component-scan base-package="jp.co.xxx.*" /><!-- my package. contains WebMvcConfiguration class -->
<annotation-driven />
<!-- aop -->
<aop:aspectj-autoproxy />
</beans:beans>
Note.
When server starts, configureMessageConverters method was called.
(Breakpoint confirmation)
I am using AbstractJsonpResponseBodyAdvice subclass for JSONP
(I removed this class, but nothing was changed.)
I used below as reference.
How to configure MappingJacksonHttpMessageConverter while using spring annotation-based configuration?
http://www.baeldung.com/spring-httpmessageconverter-rest
SpringMVC version is 4.1.6
P.S.
In JSONSerializer case is below.
#Configuration
#EnableWebMvc
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
#Autowired
protected CustomObjectMapper mapper;
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(converter());
super.configureMessageConverters(converters);
}
#Bean
protected MappingJackson2HttpMessageConverter converter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(mapper);
return converter;
}
}
ObjectMapper
#Component
public class CustomObjectMapper extends ObjectMapper {
private static final long serialVersionUID = -6987863269632420904L;
public CustomObjectMapper() {
setSerializationInclusion(Include.NON_NULL);
enable(SerializationFeature.INDENT_OUTPUT);
SimpleModule module = new SimpleModule();
module.addSerializer(DateTime.class, new DateTimeSerializer());
registerModule(module);
}
}
In each case I had no error. But customization didn't work.
In the configureMessageConverters method, if you are not covered and no other converter is added, converters are empty, and WebMvcConfigurationSupport will call addDefaultHttpMessageConverters, which will configure the default converter, which contains the default MappingJackson2HttpMessageConverter.
So adding MappingJackson2HttpMessageConverter in extendMessageConverters will not work.
There are two solutions:
You add the required converter in the configureMessageConverters method itself
To determine the type of converter in extendMessageConverters, set the required properties
sorry,i speek broken english.
I was having this problem as well and discovered this problem, thanks to another site:
#EnableWebMvc is equivalent to in XML based configuration.
If you have BOTH, then the extendMessageConverters doesn't seem to be effective. As soon as I removed the XML entry, bingo.. the custom converters started working.

Spring java config EJB proxy not working

I have a problem getting EJB beans working when using Spring's java config classes.
Specifically I have the following that works:
#Configuration
#ComponentScan(basePackages = "com.company.web.config")
#ImportResource(value = {"classpath:spring-beans.xml"})
public class AppConfig {
}
#Configuration
#ComponentScan(basePackages = "com.company.web")
public class WebConfig extends WebMvcConfigurationSupport {
// basic Spring MVC setup omitted
}
My spring-beans.xml looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd">
<jee:local-slsb id="fooService" jndi-name="java:app/model/FooServiceBean!com.company.ejb.FooService"
business-interface="com.company.ejb.FooService" />
</beans>
With this configuration, everything works, and I can do this:
#Controller
public class HomeController {
private final FooService fooService;
#Autowired
public MyPageController(FooService fooService){
this.fooService = fooService;
}
// request methods
}
Now i try to get rid of the XML file. According to the documentation the local-slsb should be equivalent
<bean id="fooService"
class="org.springframework.ejb.access.LocalStatelessSessionProxyFactoryBean">
<property name="jndiName" value="java:app/model/FooServiceBean!com.company.ejb.FooService"/>
<property name="businessInterface" value="com.company.ejb.FooService"/>
</bean>
However, if I remove the #ImportResource from AppConfig and put this #Bean method instead, deployment fails because the Controller cannot be instantiated (no autowire candidates found for FooService):
#Bean
public LocalStatelessSessionProxyFactoryBean fooService(){
LocalStatelessSessionProxyFactoryBean factory = new LocalStatelessSessionProxyFactoryBean();
factory.setBusinessInterface(FooService.class);
factory.setJndiName("java:app/model/FooServiceBean!com.company.ejb.FooService");
return factory;
}
Any ideas why this doesn't work? I am using Spring version 4.0.2.
It seems that the issue was related to the order in which configuration was read, and possibly double configuration loading.
Specifically, introducing a separate configuration class and importing it before WebConfig seems to do the trick, like so:
#Configuration
#Import({EJBConfig.class, WebConfig.class})
public class AppConfig {
}
#Configuration
public class EJBConfig {
#Bean
public LocalStatelessSessionProxyFactoryBean fooService(){
LocalStatelessSessionProxyFactoryBean factory = new LocalStatelessSessionProxyFactoryBean();
factory.setBusinessInterface(FooService.class);
factory.setJndiName("java:app/model/FooServiceBean!com.company.ejb.FooService");
return factory;
}
}
#Configuration
#ComponentScan(basePackages = "com.company.web")
public class WebConfig extends WebMvcConfigurationSupport {
// basic Spring MVC setup omitted
}

AOP using AspectJ not working in spring?

My Aspect class will be ,
#Configuration
#EnableAspectJAutoProxy
#Component
#Aspect
public class AspectClass {
#Before("execution(* com.pointel.aop.test1.AopTest.beforeAspect())")
public void logBefore(JoinPoint joinPoint) {
System.out.println("Before running the beforeAspect() in the AopTest.java class!");
System.out.println("Hijacked Method name : " + joinPoint.getSignature().getName());
System.out.println("************************");
}
}
My other java Class
public class AopTest {
public void beforeAspect() {
System.out.println("This is beforeAspect() !");
}
}
My Main Class is
public class MainMethod {
public static void main(String[] args) {
ApplicationContext context = new FileSystemXmlApplicationContext("ApplicationContext/applicationContext.xml");
AopTest test = (AopTest)context.getBean("bean1");
test.beforeAspect();
}
}
My applicationContext.xml is ,
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd ">
<bean id="bean1" class="com.pointel.aop.test1.AopTest" />
</beans>
In this the #Before("execution(* com.pointel.aop.test1.AopTest.beforeAspect())") in the AspectClass will not be executed before the beforeAspect() in the AopTest , when running Main method.
Good answers are definitely appreciated.
First of all if you're going to use an annotation based configuration, use AnnotationConfigApplicationContext instead of FileSystemXmlApplicationContext. And get rid of the applicationContext.xml file and simply add a #Bean method in your configuration class. Something like this:
#Configuration
#EnableAspectJAutoProxy
#ComponentScan(basePackages = "your.aspect.package")
public class AspectConfig {
#Bean
public AopTest aopTest() {
return new AopTest();
}
}
In your main
public class MainMethod {
public static void main(String[] args) {
AnnotationConfigApplicationContextcontext = new AnnotationConfigApplicationContext(AspectConfig.class);
// don't forget to refresh
context.refresh();
AopTest test = (AopTest)context.getBean("aopTest");
test.beforeAspect();
}
}
In AspectClass you should have #Component, #Aspect, and your method should have the advice or pointcut annotation like #Before. It needs to be a #Component, so that Spring knows to scan it.
Here some code need to add in xml to use annotations-
1.for #component annotation.
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"
2.after that use component scan to get all annotated bean class which use #component annotation,and use aop autoproxy-
<context:annotation-config/>
<context:component-scan base-package="mypackage"></context:component-scan>
<aop:aspectj-autoproxy>
</aop:aspectj-autoproxy>
for examples visit-www.technicaltoday.com/p/spring.html
You are missing the point cut definition in your aspect class.
For example;
#Pointcut("execution(* *.advice(..))")
public void logBefore(){}
#Before("logBefore()")
public void beforeAdvicing(){
System.out.println("Listen Up!!!!");
}
You first have to defin the point to weave your aspect to. You do this by using Point cuts.It is the point cut name you give within your #Before annotation. Have a look at my blog post for more information # http://dinukaroshan.blogspot.com/2010/06/aop-with-spring.html
I don't see your AspectClass in the beans configuration. You should also declare it as a Bean.

AOP with Spring 3 using Annotations

I am trying to get Aspect working with Spring 3 and annotations.
#Aspect
public class AttributeAspect {
#Pointcut("#annotation(com.mak.selective.annotation.Attribute)")
public void process(){
System.out.println("Inside Process ....");
}
#Around("process()")
public void processAttribute(){
System.out.println("Inside Actual Aspect ..");
}
}
XML:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<aop:aspectj-autoproxy proxy-target-class="false" />
<context:component-scan base-package="com.mak.selective.annotation.*" />
<bean name="attribute" class="com.mak.selective.annotation.AttributeAspect"/>
</beans>
MY Test to test the Aspect:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("/springcontext/*.xml")
public class AttributeTest {
#Attribute(tableName = "firstTable", columnName = "New Column")
private void getAttribute() {
System.out.println("Inside Attribute call...");
}
#Test
public void testAttributeAspect() {
getAttribute();
}
}
With this code i can only see "Inside Attribute call..." but nothing from Aspect.
Please guide.
Got this working by making a new Object (Component) and injected to the Junit test class.
Good to see that you got it working from XML, but you could have also done it from annotations.
The issue is that the #Aspect annotation is not a Spring stereotype, so the scanner is not registering the aspect as a Spring Bean. Just add either #Service or #Component above or below #Aspect and it will be registered.
Also, either directly name the bean (e.g., #Service("myNamedService")) or have it implement an interface (e.g., public class AttributeAspect implements IAspect {), as per standard Spring design.
You need to use real AspectJ if you want to intercept invocations of methods within the same bean form where it is invoked. (What you have done, should work if the method testAttributeAspect() is located in an other bean.)
How to do real AspectJ?
Using the AspectJ compiler and weaver enables use of the full AspectJ language, and is discussed in Section 7.8, “Using AspectJ with Spring applications”.
#See Spring Reference
A few things:
Firstly, when you do around advice you need to write the advice method like this:
#Around(...)
public void aroundAdviceMethod(ProceedingJoinPoint pjp) throws Throwable {
try {
System.out.println("before...");
pjp.proceed();
}
finally {
System.out.println("After...");
}
}
But also (and this at least applies when you're using proxies, not entirely sure in your case), the method you're putting advice on needs to be public (yours isn't), spring managed (via #Component or otherwise) and called external from the class so the proxy can take effect (also not the case in your example). So you need something like this:
#Component
public class SomeClass {
#Attribute
public void someMethodCall() {
System.out.println("In method call");
}
}
public class SomeUnitTest {
#Autowired SomeClass someClass;
#Test
public void testAspect() {
someClass.someMethodCall();
}
}

Categories

Resources