Spring Boot custom annotations - java

In all of my projects I need the same WebSecurityConfig. So I copy the same implementation of extending WebSecurityConfigurerAdapter.
I like to add this to a common library I am using in every project and create a annotation for that.
But the annotation class cannot have a superclass.
I tried this:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
#Configuration
#EnableWebSecurity
public #interface EnableGlobalSecurity extends WebSecurityConfigurerAdapter {
}
Is there a better way to get this working? I just want to add my SecurityConfiguration by adding an annotation or something similar.

You should be able to just #Import your shared #Configuration class in every application that should use it.
Another way would be to create a custom auto-configuration. This way, declaring a dependency on your shared library would suffice.

Related

Spring AutoConfiguration manul import all components

I have the following autoconfigure class.
#Configuration
#ConditionalOnWebApplication
#EnableConfigurationProperties({LoggerProviderProperties.class})
#Import({LoggerController.class, LogService.class, LogConfig.class})
public class ProviderAutoConfiguration {
}
I need to import all the components, services, configurations using #import annotation, otherwise for example, when I remove LogService.class (LogController autowires LogService) from #Import parameters, it throws the following error
Consider defining a bean of type 'com.log.LogService' in your configuration.
Do I really have to include all of them manuelly as shown above, or is there any other way to automatically detect classes annotated Service, Component or Configuration?
!This is starter library, not a executable app!
The problem with your "library" is that it already needs a lot of moving parts, like Spring Data JPA, properly setup JPA. If that isn't available it will fail, or if you add #EnableJpaRepositories and/or things like #ComponentScan and #EntityScan it will (quite severely) interfere with the (auto)configuration of Spring Boot or the clients. Which is what you want to prevent.
Instead of all those annotations what you need to do is
Conditionally enable #EnableJpaRepositories or just include the dependency and let the auto-configuration kick in (I suggest the latter)
Don't add #ComponentScan, #EntityScan etc. instead use #AutoConfigurationPackage which is designed for starters.
#Configuration
#ConditionalOnWebApplication
#EnableConfigurationProperties({LoggerProviderProperties.class})
#AutoConfigurationPackage
public class ProviderAutoConfiguration {
}
NOTE: This assumes that the ProviderAutoConfiguration is in the same or a higher package then your other classes. If not specify the basePackages in the #AutoConfigurationPackage.
You can use #ComponentScan to specify the packages you want to scan to find configurations and/or components to load.
Assuming you are using Spring Boot, at least so it seems according to your tags, you should take a look at #SpringBootApplication.
#SpringBootApplication encapsulates #Configuration, #EnableAutoConfiguration, and #ComponentScan annotations with their default attributes. The default value for #ComponentScan means that all the sub packages on the package the #ComponentScan is used are scanned. That is why it is usually a good practice to include the main class in the base package of the project.
If your components, services, configurations are under com.log as direct class or in sub-package, you can use #ComponentScan(basePackages="com.log.*")
#Configuration
#ConditionalOnWebApplication
#EnableConfigurationProperties({LoggerProviderProperties.class})
#ComponentScan(basePackages="com.log.*")
public class ProviderAutoConfiguration {
}

Should I add #Component annotation to all classes in Java Spring program?

Currently I use #Component only on my Views, Controllers and Models.
To be accurate, I use #RestController for Views, #Service for Controllers and #Component for Models (because I want to use Hibernate as an ORM provider)
My problem is that I also use #Autowired constructors which means that I can use only #Component based Objects in my constructor.
Sometimes I need to create a Controller that takes none-Component class. As an example - to add Config clas besides other #Component objects to my constructor .
What should I do in general:
1) Add #Component annotation to all Java classes.
2) Add #Component only to those classes that I need ? (which means that some my Config classes will have #Component when others Config classes will not.)
3) Not use #Autowired in situations like this, create a Controller in a regular way ?
4) Not use #Autowired constructors at all ?
5) Other ideas ?

Spring dependency injection - best design pattern of configuration

Right now i have a inherited project that is using annotation based spring dependency injection. So all classes are simply marked with #Component (or specific stereoTypes like #service, #Repository,#RestController, etc). This makes it a little hard to find where the dependency is located and i was thinking to change it so that each package has its own dependency configuration and then add each package to the #ComponentScan afterwards.
So for example if i had a package called com.mycoolpackage.login and mycoolpackage.networking
then i'd have a Spring configuration like this in first package:
#Configuration
public class LoginDIConfig {
#Bean
public LoginServiceImpl loginServiceImpl() {
return new LoginServiceImpl();
}
}
and in the second package i'd have the following:
#Configuration
public class NetworkDIConfig {
#Bean
public NetworkServiceImpl networkServiceImpl() {
return new NetworkServiceImpl();
}
}
and my#ComponentScan would look like this:
#ComponentScan(basePackages = {"com.mycoolpackage.login","com.mycoolpackage.network"})
So i have two questions about this approach.
How can i use a #Service annotation instead of bean here
Do you think this design is more easier as it tells you what your package dependencies are very easily instead of hunting them
down.
If you want to configure some been properties manually then you should go for above configuration else you should stick with exiting one.
This makes it a little hard to find where the dependency is located
#Autowire Or #Inject annotation will always lead you to dependency class.

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.

Should I annotate configuration class as #Configuration for testing?

I spent some time resolving problem with missing org.joda.time.DateTime->java.util.Date converter in Spring Data (which should be enabled by default when Joda-Time is on a classpath). I have found a reason, but it generated a question about #Configuration annotation in Spring.
Standard application config using AbstractMongoConfiguration from spring-data-mongodb:
#Configuration
#ComponentScan
#EnableMongoRepositories
public class AppConfig extends AbstractMongoConfiguration { ... }
A test which explicit uses AppConfig class (with Spock, but internally mechanisms provided by spring-test are used):
#ContextConfiguration(classes = AppConfig)
class JodaDocRepositorySpec extends Specification {
#Autowired
private JodaDocRepository jodaDocRepository
def "save document with DateTime"() {
given:
def jodaDoc = new JodaDoc(DateTime.now())
when:
def savedJodaDoc = jodaDocRepository.save(jodaDoc)
then:
savedJodaDoc.id
}
}
It works fine. But when #Configuration annotation in AppConfig is removed/commented:
//#Configuration
#ComponentScan
#EnableMongoRepositories
public class AppConfig extends AbstractMongoConfiguration { ... }
the test fails with:
org.springframework.core.convert.ConverterNotFoundException:
No converter found capable of converting from type org.joda.time.DateTime to type java.util.Date
AFAIK it is not needed to use #Configuration for the configuration class when it is explicit registered in the context (by classes in #ContextConfiguration or a register() method in AnnotationConfigWebApplicationContext). The classes are processed anyway and all declared beans are found. It is sometimes useful to not use #Configuration to prevent detecting by a component scan when there are 2 similar configuration classes in the same packages in a test context used by different tests.
Therefor I think it could a bug in Spring which causes to different internal beans processing in the context depending on an usage or not a #Configuration annotation. I compared Spring logs from these two cases and there are some differences, but I'm not able to determine what are they caused by in the Spring internal classes. Before a bug submission I would like to ask:
My question. Is there an explicable reason why Spring for the same configuration class (pointed explicit in #ContextConfiguration) uses (or not) converters for Joda-Time depending on an existence of a #Configuration annotation?
I created also a quickstart project reproducing the issue. spring-data-mongodb 1.3.3, spring 4.0.0, joda-time 2.3.
It's everything OK in this behaviour. AbstractMongoConfiguration is annotated by #Configuration, but in fact this annotation is not #Inherited, so you have to explicitly annotate your class.
When you remove #Configuration annotation then your AppConfig class is not a full configuration. It's processes as a lite configuration just because it contains methods annotated by #Bean - please refer to methods in org.springframework.context.annotation.ConfigurationClassUtils
isFullConfigurationCandidate()
isLiteConfigurationCandidate()
isFullConfigurationClass()
Finally only full (annotated by #Configuration) configuration classes are processes and enhanced by configuration post processors - look at ConfigurationClassPostProcessor.enhanceConfigurationClasses()

Categories

Resources