I have come across so many tutorials about configuration files for java SpringMVC projects and usually have the #Configuration at their class name but they never mention where exactly to place these files.
For example I have learnt that I might be able to change Spring Data Rest rest api by extending the RepositoryRestMvcConfiguration.
1) I want to be able to be able to have longer urls for the repositories so instead of having api/amazonproducts I could have api/amazon/products. Apparently this is impossible. I end up having;
#RepositoryRestResource(collectionResourceRel = "amazonproducts", path = "amazonproducts")
#CrossOrigin
public interface AmazonProductRepository extends PagingAndSortingRepository<AmazonProduct, Long> {
https://docs.spring.io/spring-data/rest/docs/current/api/org/springframework/data/rest/webmvc/config/RepositoryRestMvcConfiguration.html
All I have to do is for example create class like;
class CustomRestMvcConfiguration extends RepositoryRestMvcConfiguration {
#Override
#Bean
public HateoasPageableHandlerMethodArgumentResolver pageableResolver() {
HateoasPageableHandlerMethodArgumentResolver resolver = super.pageableResolver();
resolver.setOneIndexedParameters(true);
return resolver;
}
}
I don't know in which file/folder to place this code. I am using Eclipse Java EE Oxygen. I have created a maven project and I am currently testing it on spring-boot
You can place #Configuration annotated classes in any package you want, as long as the package is included in the component scanning.
In Spring Boot, that by default means in the same package as the class with #SpringBootApplication, or any subpackage thereof, same as for all other classes managed by Spring.
Other than that, Spring doesn't care about package names.
Related
So I have a React app I want to serve from my Spring app (ala this blog). As part of my gradle build task, I run the npm build command and copy the resulting files to /build/resources/main/static. This works fine and I can access my app at mysite.com/index.html, but I want to control who has access more granularly. As such, I applied #EnableWebMvc to my app, but from there, I can't seem to get my API controller to actually serve the view from the build directory. It seems no matter where I put it, it doesn't like serving directly from /build. Any way to make this work?
The handler looks like:
#Controller
class MyController {
#RequestMapping("/")
fun index(): String {
return "index"
}
}
As indicated in the Spring Boot documentation, you do not need - in fact, it is not recommended - to use #EnableWebMvc when using Spring Boot. They state, when describing Spring MVC auto-configuration:
Spring Boot provides auto-configuration for Spring MVC that works well with most applications.
And:
If you want to keep those Spring Boot MVC customizations and make more MVC customizations (interceptors, formatters, view controllers, and other features), you can add your own #Configuration class of type WebMvcConfigurer but without #EnableWebMvc.
In the guide, they continue when describing static content handling:
By default, Spring Boot serves static content from a directory called /static (or /public or /resources or /META-INF/resources) in the classpath or from the root of the ServletContext. It uses the ResourceHttpRequestHandler from Spring MVC so that you can modify that behavior by adding your own WebMvcConfigurer and overriding the addResourceHandlers method.
In your example, following this advice, you can indicate the static resource handling location with something like (sorry, I am not fluent in Kotlin, forgive for write the example in Java):
#Controller
public class MyController implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceHandler("/static/**")
.addResourceLocations("classpath:/static")
;
}
#GetMapping(path = "/")
public String index() {
return "index";
}
}
Please, adapt the paths in addResourceHandlers to your needs.
You can of course place this method in an ad hoc #Configuration.
Having said that, if when you say granular you mean security, the best approach you can take is to configure Spring Security and provide the necessary authorization rules: please, see the relevant documentation.
I've got a project (this will be used as a dependency) which uses SpringBoot and which populates a POJO from a queues.properties file in the following way:
#Component
#PropertySource({"classpath:queues.properties"})
#ConfigurationProperties("queue")
public class QueuesConfig {
private String messagingBrokerXml;
private String messagingBrokerJolokia;
private String messagingBrokerApi;
private List<QueuesConfig.QueueModel> queues = new ArrayList();
public QueuesConfig() {
}
public String getMessagingBrokerXml() {
return this.messagingBrokerXml;
}
...
By dragging this dependency in a parent SpringBoot project which has a "queues.properties" file on its classpath, QueuesConfig object gets populated with the right values.
I am currently trying to achieve the same behaviour by using this dependency in a Plain Spring project. I can confirm that the PropertySource annotation gets "executed" and that the queues.properties file is part of the StandardServletEnvironment (being an entry in the propertySourceList).
The thing is that the "ConfigurationPropertiesBindingPostProcessor" bean is not being registered (not part of the singletonObjects) and therefore the code which is supposed to populate the POJO is not being executed.
Is there any workaround for this?
Many thanks !
Try to add this in your parent Spring #Configuration class:
#EnableConfigurationProperties(QueuesConfig.class)
For more details read this section of Spring Boot documentation. It is few screens of text, but it worth it ;-)
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-typesafe-configuration-properties
Probably it worked well in your test app because you used some hi-level magic with #SpringBootApplication :)
Is every rest service starting with extending that application class and defining applicationpath? What is the lifecyce of that application class itself? Here is an example:
import javax.ws.rs.core.Application;
#javax.ws.rs.ApplicationPath("resources")
public class ApplicationConfig extends Application {}
Is this a servlet? Is it always alive? How shall I understand this class? Is it a cdi bean? Does the server creates this class on every request?
What is Application?
Application is a deployment agnostic abstract class provided by JAX-RS for configuring and registering the components of a JAX-RS application and it's also used to supply additional metadata to the application.
Application is one of the types that can be injected using the #Context annotation. For more details, refer to this answer.
Subclasses of Application
Application subclasses can implement methods such as getClasses(), getSingletons() and getProperties() for configuring and registering components and properties.
Application subclasses can be annotated with #ApplicationPath, defining the base URI for the JAX-RS resource classes (classes annotated with #Path). Application subclasses are instantied once when the web application starts and they are managed by the JAX-RS runtime.
The simplest implementation possible is as following:
#ApplicationPath("api")
public SampleApplication extends Application {
}
In the example above no resources classes or providers are registered, so the JAX-RS runtime will scan the classpath for JAX-RS components and will register them automatically.
However, according to this post from Jakub Podlesak, this approach is discouraged in production environments:
The above example works great. When started, the application just scans the actual class-path, and adds every single JAX-RS component class found there to the actual runtime configuration. Isn't is great? Frankly, this kind of configuration could work just fine. Until someone changes either the system configuration (system class-path) or the way how you application is being packaged (a new 3rd party component could be added/removed from the application class-path then). These changes could be out of your control and if one of them happens, you application configuration could break. For this reason, it is not wise to use this kind of configuration in a production environment.
Jersey, the JAX-RS reference implementation, provides the ResourceConfig class. Compared to Application, ResourceConfig provides advanced capabilities to simplify registration of JAX-RS components, such as scanning for root resource and provider classes in a provided classpath or a in a set of package names, etc. For more details, refer to the Jersey documentation.
Working with multiple Application subclasses
Is also worth mentioning that you are not restricted to a single Application subclass per web application. The same WAR can have multiple Application subclasses. For more details, have a look at this post from Adam Bien:
To deploy multiple JAX-RS applications with different URIs in one WAR you will have to create one javax.ws.rs.core.Application subclass per such an application (or use web.xml for this purpose). Obviously the in Java EE ubiquitous Convention over Configuration (or Configuration by Exception) cannot work any more: you will have to explicitly configure resources in each subclass by overriding the method getClasses or getSingletons:
#Path("first")
public class FirstResource {
#GET
public String first() {
return "first";
}
}
#ApplicationPath("one")
public class JAXRSConfigurationOne extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new HashSet<>();
resources.add(FirstResource.class);
return resources;
}
}
#Path("second")
public class SecondResource {
#GET
public String first() {
return "second";
}
}
#ApplicationPath("two")
public class JAXRSConfigurationTwo extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new HashSet<>();
resources.add(SecondResource.class);
return resources;
}
}
Both JAX-RS applications become accessible through distinct URIs: http://localhost:8080/multiple-roots/one/first and http://localhost:8080/multiple-roots/two/second
What if no Application subclass is present?
If no Application subclass is present, the JAX-RS implementations are required to add a servlet and set its name to javax.ws.rs.Application and to automatically discover all resource classes and providers which must be packaged with the application.
For further details, have a look at the chapter 2 of the JAX-RS 2.1 specification.
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.
According to official doc:
Annotation Type Configuration
Indicates that a class declares one or more #Bean methods and may be
processed by the Spring container to generate bean definitions...
#Configuration classes may be composed using the #Import annotation,
not unlike the way that works in Spring XML. Because
#Configuration objects are managed as Spring beans within the
container..
But i can also use #Configuration annotation without #Import. I have tested the code listed below and it works as expected. So what is the purpose to use #Import?
DispatcherServletInitializer
public class ApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { WebConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
WebMvcConfigurerAdapter
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "package.name" })
// #Import(OptionalConfig.class)
public class WebConfig extends WebMvcConfigurerAdapter {
// ...
}
OptionalConfig
#Configuration
public class OptionalConfig {
#Bean(name = "myClass")
public MyClass myClass() {
return new MyClass();
}
}
Service
#Service
public class MyServiceImpl implements MyService {
#Autowired
private MyClass myClass; // yes, it works
// ...
}
If component scanning is enabled, you can split bean definitions in multi #Configuration classes without using #Import. And you don't need to provide all of them to the application context constructor.
I think the main purpose for #Import is to provide you a way to simplify multiple configurations registration if you'd like to avoid component scanning (as of Spring Framework 4.2, per reference manual).
There's a note in Spring Reference Documentation about #Import usage:
As of Spring Framework 4.2, #Import also supports references to regular component classes, analogous to the AnnotationConfigApplicationContext.register method. This is particularly useful if you’d like to avoid component scanning, using a few configuration classes as entry points for explicitly defining all your components.
Thus far, we've seen how to break up bean definitions into multiple #Configuration classes and how to reference those beans across #Configuration boundaries. These scenarios have required providing all #Configuration classes to the constructor of a JavaConfigApplicationContext, and this is not always ideal. Often it is preferable to use an aggregation approach, where one #Configuration class logically imports the bean definitions defined by another.
The #Import annotation provides just this kind of support, and it is the direct equivalent of the <import/> element found in Spring beans XML files.
http://docs.spring.io/spring-javaconfig/docs/1.0.0.M4/reference/html/ch04s03.html
I found a use of using the #Import annotation. I don't think it's the use case.
If you are developing a set of libraries using Spring, probably you don't have a SpringBootApplication. So, you have not enabled any auto-scan to resolve beans.
If a bean declared in a configuration file in the library library-a is referred through dependency injection in library-b you need to use #Import to tell Spring how to resolve the bean.
As we said, in library-a you have this configuration file.
#Configuration
public class ConfigurationA {
#Bean
public BeanA beanA() {
return new BeanA();
}
}
In library-b you must have this configuration file if you want to use BeanA
#Configuration
#Import(ConfigurationA.class)
public class ConfigurationB {
#Bean
public BeanB beanB(BeanA beanA) {
return new BeanB(beanA);
}
}
Hope it helps.
With component scanning enabled it's difficult to immediately see where #Import adds value if your view of the world is limited to your own application and its packages. Where it can help is if you are importing bean libraries with their own package structure that you don't want to component scan.
You can place such libraries on your classpath and use #Import to cherry-pick #Configuration classes from within them. That's why it's often referred to as composition because you are composing your #Configuration class from multiple sources.
A typical use case of #Import is when teams develop REST services and realize they need some common configuration.
Every service will have its own namespace i.e. org.mybusiness.specific and will have its #SpringBootApplication (and therefore component scan root) start at this package.
On the other hand, the common library will have its namspace set to org.mybusiness.common and will therefore be out of reach for component scanning.
Thus the need to reference the common configuration class using #Import(CommonConfig.class)
#Import works great when for some reasons you need to register not all but some of the components from a package. In such case #ComponentScan would be too complicated.
See details in the Spring boot component scan include a single class question.