Spring #Configuration and <context:component-scan /> - java

I have a scenario configuring Spring Security on embedded Jetty which seems to be somewhat solved if I make use of JavaConfig to configure the Jetty server.
As a result, it's looking like JavaConfig rather than XML might be the better option for large chunks of the project. However, there are some niceties in the XML namespaces, like <context:component-scan /> which aren't readily available in a #Configuration setting.
I have discovered that ApplicationContextAware is honored for #Configuration classes, so the following is possible
#Configuration
public class FooConfig implements ApplicationContextAware {
#Override
public void setApplicationContext(ApplicationContext applicationContext) {
((AnnotationConfigApplicationContext) applicationContext).scan("org.example");
}
}
The alternative, which is documented, is to have the #Configuration class use an #ImportResource annotation and pull in an existing XML file:
#Configuration
#ImportResource("applicationContext-withComponentScan.xml")
public class BarConfig {}
I guess the question is "Is it bad form to abuse ApplicationContextAware in this way, or is it really not abuse"? Something just feels oddly dirty about the approach so I'd not be surprised if the Spring guys had covered this in some way or another that I've not spotted.
For the interested, the problem relates to scanning a Jersey setup with #Resource and #Provider classes that I'd rather not have to manually manage entries in a class/XML configuration.

Now that Spring 3.1 is ready and out, you can safely use #ComponentScan if you are on Spring 3.1. It's not only for Spring MVC as one of the outdated answers mentions. You can use it as follows:
#Configuration
#ComponentScan({"com.foo.bar", "org.foo.bar"})
public class AppConfig{ /** config code */ }
Here is the documentation http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/context/annotation/ComponentScan.html

Is it bad form to abuse ApplicationContextAware in this way, or is it really not abuse
Yes, this is bad form. If you're going to fetch things out of the context manually, you may as well not bother with dependency injection in the first place.
However, your second option (#ImportResource("applicationContext-withComponentScan.xml")) is a good one - this is current best practice when you want to use these XML macros in combination with annotation-style config.
A third option is to use the current milestone build of Spring 3.1, which adds a way of doing these things all in Java, using #Feature. This is not yet production-ready, though.

Check this link out as well. It is a bit more specific (for a web application) but it has a very nice code example for the scanning, specifically: http://static.springsource.org/spring/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/EnableWebMvc.html
from that link:
#ComponentScan(basePackages = { "org.example"} )

Related

CXF SpringComponentScanServer usage

I want to configure CXF to auto-scan for resources, providers, features, and the lot. In my search I came across the SpringComponentScanServer, which sounds like something I need. Unfortunately, documentation about this class is virtually non-existent.
When you have classes annotated with #javax.ws.rs.ext.Provider, they get picked up by CXF as expected. When you have a feature annotated with org.apache.cxf.annotations.Provider, it will also get picked up by CXF.
But what if you have a third-party feature that does not have this annotation?
For example, the CXF LoggingFeature? You cannot, as far as I know, add an annotation to a class if you can't change it's source code.
I came up with the following, hideous, solution, but surely, there must be a better way to do this???
#Configuration
#Import(SpringComponentScanServer.class)
public class CxfConfig {
#Component
#Provider(Provider.Type.Feature)
static class MyLoggingFeature extends LoggingFeature {
}
}
Here, I basically extend the existing LoggingFeature, only to add the #Provider annotation.
I found the following example CXF JAXRS Spring Boot example, which does what I want with the Swagger2Feature. That works, but only starting from CXF 3.1.6, and only for the Swagger2Feature. Not for LoggingFeature.
So my question is: is there a less hideous way to add the LoggingFeature?

Configure RequestMappingHandlerMapping to not decode url

I have a Spring MVC 3.2.8 application with Java configuration. I want to disable url decoding as I have this issue with / in the uri. Spring 3.2.8 should fix this.
The problem is, I can't set Url decoding to false in RequestMappingHandlerMapping. I tried to override it with:
#Configuration
public class MobileWebPublicConfig extends WebMvcConfigurationSupport {
#Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping handlerMapping = super.requestMappingHandlerMapping();
handlerMapping.setUrlDecode(false);
return handlerMapping;
}
}
But when I do this, it breaks my application an auto-wiring stops working.
What am I missing?
UPDATE: container is Tomcat 6, there is no stacktrace related, the app fails when trying to access an autowired element due to it being null. Commenting the configuration above makes it work fine.
The documentation for #EnableWebMvc describes three levels of customization for tailoring your configuration. You can:
Use #EnableWebMvc on its own to import the standard configuration.
Use #EnableWebMvc with configuration classes that extend WebMvcConfigurerAdapter; the subclasses will have their implemented methods called automatically to apply your changes to the standard configuration.
Don't use #EnableWebMvc, but instead make your configuration class extend WebMvcConfigurationSupport to gain full control over your configuration.
However, what the documentation does not make clear is that if you go for option 3 it will not automatically apply the methods implemented in classes that extend WebMvcConfigurerAdapter.
As others have said, we really need to see your full configuration, but if simply extending WebMvcConfigurationSupport and removing #EnableWebMvc breaks other parts of your configuration, my guess is that you are still using WebMvcConfigurerAdapter somewhere else in your config.
If this is the case, you have two options:
Rewrite all your configuration that uses WebMvcConfigurerAdapter and move the code into a single configuration class that extends WebMvcConfigurationSupport.
Extend DelegatingWebMvcConfiguration instead of WebMvcConfigurationSupport. This will give you all the standard configuration behaviour that you normally get when using #EnableWebMvc but still allow you to override methods as required. Note that in any method you override, you'll also need to call the equivalent method in super() if you want to keep the default behaviour too.
EDIT: Also make sure that you don't have #EnableWebMvc annotation somewhere since this annotation will import the original WebMvcConfigurationSupport and not the extended version.
WebMvcConfigurationSupport javadoc says
It is typically imported by adding #EnableWebMvc to an application #Configuration class. An alternative more advanced option is to extend directly from this
class and override methods as necessary remembering to add
#Configuration to the subclass and #Bean to overridden #Bean methods.

Hard-coded #RequestMapping URL in Spring MVC Controller

I'm studying Spring 3 and I'm using it in a simple web-application.
Now I'm implementing a Spring MVC Controller using annotations, and I'm wondering:
Is there any best practice using #RequestMapping annotation?
I mean: I've seen that usually the URL mapped in this annotation is hardcoded in the class...
Is there a way to pass the URL in a 'loosely coupled way' (to obtain a more reusable class)?
I know that there are some wild cards that can be used, but I think that isn't the solution... Am I wrong?
EDIT:
I add an example to better explain my doubt.
Suppose I want my controller to be triggered by a request to /foo/bar/baz/mypage.htm, in my controller the handler method will be annotated with #RequestMapping("/foo/bar/baz/mypage").
Now I decide to change the URL triggering my controller into /foo/bar/otherpage.htm, so i need to edit my class, put #RequestMapping("/foo/bar/otherpage") on my handler method, recompile the project and deploy it again.
It seems to me not so practical...
Currently annotated controllers aren't very configurable.
As far as I know, the only possible approach to this problem is to use alternative HandlerMappings in order to configure "base URLs" of controllers. For example, as follows:
// Note the absense of #Controller to prevent this controller
// from being discovered by DefaultAnnotationHandlerMapping
public class FooController {
#RequestMapping("/list") public String list(...) { ... }
#ReqeustMapping("/save") public String save(...) { ... }
}
.
<bean
class = "org.springframework.web.servlet.mvc.support.ControllerBeanNameHandlerMapping" />
<bean name = "/foo" class = "FooController" />
<bean name = "/bar" class = "FooController" />
In this example two instances of FooController handle /foo/list, /foo/save, /bar/list and /bar/save respectively.
The upcoming Spring 3.1 will have an improved Spring 3.1 architecture (Spring 3.1 M2: Spring MVC Enhancements) that seems to be more flexible, though I haven't checked it yet.
I think you are trying to solve the wrong problem. If you wanted to change the pages that matched a controller you'd need to change a file somewhere. Would you rather change the file with the related code underneath it, or would you rather work with some XML files that specifies the URL and the class, and then you have to worry about the file being in the right place during runtime?
As there should be almost no code in your controller anyway, you should think of your controllers as compilable configuration files. Also, if you are using a build system like Maven or Ant and not compiling individual files by hand using Javac then compilation time shouldn't be an issue. If it becomes one, it's probably time to split your project into sub-projects.
I think you should just embrace this and see that it is probably not the issue you think it is. Also, did you know that controllers can match to expressions and not just literal strings? That gives you some flexibility in your naming.
If you really want to, you could just fall back to the Spring 2.0 style XML configuration, but I don't think anyone would recommend that.
I think that is not a best practice, but have you tryed with #PathVariable annotations?
#RequestMapping(value="/path/{word}", method=RequestMethod.GET)
public ModelAndView myRestMethod(#PathVariable String word) {
...
}

How to enable #Required?

How to enable the #Required annotation in Java (Spring 3.1) ? Not in a xml, but in through Java. Also under which annotation I put this enabling? Under #Feature (in #FutureConfiguration or #Bean (in #Configuration) ?
Edit:
#Feature
public MvcAnnotationDriven annotationDriven(ConversionService conversionService) {
return new MvcAnnotationDriven().conversionService(conversionService)
.argumentResolvers(new CustomArgumentResolver());
}
Does this enables all annotations?
#anubhava's answer works, but he's referenced the Spring 2.0 manual, which is 5 years old.
In XML config, Spring 3.x has a more elegant approach: <context:annotation-config/>. This also enabled a whole other bunch of features that you'll probably want, whereas RequiredAnnotationBeanPostProcessor only enables a few.
See Spring 3.x manual.
If you're using #Bean-style config, then annotations like #Required should already be enabled, since that's how #Bean works. However, it's possible that this is a bug - Spring 3.1 is still in early beta, and big chunks of it are likely to be broken.
Unless you really know what you're doing, I strongly recommend sticking to 3.0.x.
From the Spring manual:
There is one last little (small, tiny)
piece of Spring configuration that is
required to actually 'switch on' this
behavior. Simply annotating the
'setter' properties of your classes is
not enough to get this behavior. You
need to enable a component that is
aware of the #Required annotation and
that can process it appropriately.
This component is the
RequiredAnnotationBeanPostProcessor
class. This is a special
BeanPostProcessor implementation that
is #Required-aware and actually
provides the 'blow up if this required
property has not been set' logic. It
is very easy to configure; simply drop
the following bean definition into
your Spring XML configuration.
<bean class=
"org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
Please check: http://static.springsource.org/spring/docs/2.0.x/reference/metadata.html
Use AnnotationConfigApplicationContext if you don't want to use XML:
Standalone application context,
accepting annotated classes as input -
in particular #Configuration-annotated
classes, but also plain #Components
and JSR-330 compliant classes using
javax.inject annotations. Allows for
registering classes one by one
(register(java.lang.Class...)) as well
as for classpath scanning
(scan(java.lang.String...)).
In case of multiple Configuration
classes, Bean methods defined in later
classes will override those defined in
earlier classes. This can be leveraged
to deliberately override certain bean
definitions via an extra Configuration
class.
Sample Code:
ConfigurableApplicationContext applicationContext =
new AnnotationConfigApplicationContext(
"com.mycompany.package1",
"com.mycompany.package2",
"com.mycompany.package3"
// etc.
);
applicationContext.refresh();

Setting Up Annotation Driven Transactions in Spring in #Configuration Class

So in the latest version of Spring we are able to use the #Configuration annotation to setup our configurations for Spring. Now in JavaConfig it is possible to use the #AnnotationDrivenTx (#AnnotationDrivenTx Reference Link) annotation to setup transactions in our Config class. But since JavaConfig has been decommissioned I was wondering if anyone knew how to setup something similar without JavaConfig and without needing to add anything to the application-context.xml. Here is what I basically have for my Config class
#Configuration
#ImportResource("config/application-context.xml")
public class Config {
public #Bean DataSource dataSource() {
//get and return datasource
}
public #Bean Service1 getService1() {
//return service1Impl
}
}
And I'd like to make Service1 transactional. If anyone has any ideas on how to do this or if this is just not possible please let me know.
Thanks!
You can now use #EnableTransactionManagement.
See this post for more details: http://blog.springsource.com/2011/06/10/spring-3-1-m2-configuration-enhancements/
It seems like it isn't possible according to this forum post:
there may be a more first-class
mechanism for enabling
annotation-driven TX in #Configuration
classes in Spring 3.1, but in the
meantime, the recommended approach is
to use #ImportResource to include a
snippet of XML that declares
<tx:annotation-driven/>
Wait: but you seem to have an XML context anyway. Why not add <tx:annotation-driven/> to it and use #Transactional?
Take a look at http://blog.springsource.com/2011/02/17/spring-3-1-m1-featurespec. Spring 3.1's FeatureSpecification classes such as TxAnnotationDriven are designed to solve exactly the problem described above.

Categories

Resources