Spring require property when Spring MVC binding - java

I have a #RestController that has a #RequestMapping method. It takes one parameter that is an instance of a class, EmailTemplate:
public List<Message> sendEmail(EmailTemplate emailTemplate) {
return emailService.sendEmail(emailTemplate);
}
I would like to require that two String properties of emailTemplate not contain null or only whitespace. However, it should not be required in general. In other words, it should be required when passing to sendEmail but not necessarily in other places where the code might instantiate the class. Does Spring provide an annotated way to accomplish this?

Yes. Spring support Bean Validation. And Bean Validation allows setting groups on validation constraints.
So, just add constraints to the two fields with a group like SendEmailGroup.class, and annotate the EmailTemplate argument of sendEmail() with #Validated(SendEmailGroup.class).

Related

Is the Class with #Controller annotation a single object?

I know that two requests with same content use different threads. And I thought that different threads will create different instances with #Controller annotation. But when I run the code below, I find my thought is wrong.
Test code:
#Controller
#RequestMapping("test")
public class TestADEDSAController {
private String string = "";
#RequestMapping("controllerTest")
#ResponseBody()
public String controllerTest(#RequestParam String string) {
return this.string += string;
}
}
The first time the response content is like:
test
The second time is like:
testtest
It seems that there is only one Test instance in the JVM.
I would like to know whether it is true that there is always only one #Controller instance in the JVM? Also, where can I find a detailed introduction about this process?
By default, all bean in Spring is created as singleton (one per IOC container).
This is javadoc
(Default) Scopes a single bean definition to a single object instance per Spring IoC container.
By default, Spring creates a single shared instance of the bean. The bean scope is singleton by default. In case you need a new instance created on every request, you should define the bean scope as prototype. This can either be done by annotating the class with #Scope("prototype") or by defining the scope in the spring configuration xml as below:
<bean id="controllerId" class="com.package.name.TestADEDSAController" scope="prototype"/>
Please go through https://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch04s04.html to gain better understanding of bean scopes in spring.
No, by default objects are singletons. That mean your objects must be thread safe.
So it's a bad practice to have unsafe values like Strings in your controller (except constants).
You could have your fields corrupted if two threads go there at the same time.
Default scope is "singleton", so if you need Spring to create a new instance each time you can use #Scope("prototype") annotation in addition to #Controller annotation. There are also other web-aware scopes like request, session and global session. Read here for examples.

Less verbose #Bean

We use #Configuration classes with lots of #Bean annotated methods that essentially read like this:
#Bean
public TeamContactIndexer teamContactIndexer(GroupService groupService, ContactCrudService contactCrudService, ContactRetrieveService contactRetrieveService) {
return new TeamContactIndexer(groupService, contactCrudService, contactRetrieveService);
}
So this returns a new bean and injects other spring declared things via method arguments into the constructor by name.
The only way I know to reduce verbosity is to annotate the beans with #Component and constructor with #Autowired.
For many this is perfectly acceptable but I prefer to not litter my code with Spring annotations just to facilitate plumbing and keep a clean separation between completely spring free business logic and plumbing code in #Configuration annotated classes. I treat them as a more type safe, less verbose replacement for what we used to do in xml.
However, wouldn't it be nice if I could just go ...
#Bean
public TeamContactIndexer teamContactIndexer;
... and have spring figure out that it needs to autowire the constructor of that class (100% spring free) to produce the bean. This is not currently supported in Spring as far as I can see even though it should be quite easy to do as far as I can see. Am I missing something or is there really no way around me micromanaging constructor calls in my #Configuration classes (other than littering my code with annotations)? The vast majority of my #Bean methods should be easily replaced like this.
UPDATE
#bezmax has provided a workable approach here which is to use a component scan annotation.
#Configuration
#ComponentScan(
basePackages={"com.github.jsonj.tools"},
includeFilters = { #Filter(type = FilterType.ASSIGNABLE_TYPE, value = {JsonParser.class})})
public class JsonParserConfig {
}
I've used the above to provide a bean definition for a bean without annotations in a library that I use. This replaces the #Bean annotated factory method I had earlier. It's still somewhat verbose but at least you can put in a comma separated list of classes. The default for type is wrong for this usecase so you must specify it; likewise the package defintion is required even though it could be deduced from the class on the filter.
IMHO there is room for an obvious improvement in Spring, which is to provide an annotation that simply takes a comma separated list of classes. So, instead of scanning a package, simply list the bean classes you want initialized. There are probably still a few hairy issues with autowiring via the constructor.
This feature is implemented in Spring 4.3 (not yet released).
You can read more about that in the changelog (see 6.1)
Added:
As about registering your unannotated classes automatically, there seems to be a flexible way to achieve this using #ComponentScan annotation. This annotation allows you to specify a set of include filters, which, when matched on classes, are automatically registered as beans. I had not actually tried using more complex rules with this filter, and it seems that you have several options there (check out the documentation on #ComponentScan) but the easiest one would be something like this:
#Configuration
#ComponentScan(
value = "some.package.path",
includeFilters = {
#Filter(type = ASSIGNABLE_TYPE, value = {
MyClass1.class,
MyClass2.class,
MyClass3.class
})
})
public class WebConfig extends WebMvcConfigurerAdapter {
...

Spring auto inject with constructor via code or annotations

Given having next classes:
XRepository with declared a constructor with 1 argument (simple one,
not autowired), it has some autowired fields.
XService that uses XRepository as autowired.
XProcessor uses XService as autowired.
So I have to init XProcessor on runtime for specific value that will be used in XRepository constructor. On different calls I will have different arguments, so the injection should be on runtime.
Any idea how to achieve that using code configuration or annotations?
Remember that Spring needs to inject all the constructor parameters of Spring managed beans.
I believe you have two options:
Parse your URL info in controller and pass it through parameters down to persistence layer. This would be my preferred mechanism. You can create special DTO for passing various information down and keep your method signatures concise.
Your situation can alos be solved with request scope bean. You will
create one bean like this:
#Component
#Scope("request")
public class {
private String urlPart;
}
And you would autowire this component into XProcessor and
XRepository. Each request to your application will create new
instance of XRequestContext and you will parse your info in
XProcessor and store it into XRequestContext.
In XRepository you will use instance of XRequestContext to
retrieve information you stored in XProcessor.
You can read about request scope in Spring docs. It is like
ThreadLocal per request thread.

Specific url for controller using #PathVariable in RequestMapping issue

I am facing some difficulties when trying to create a certain url for #RequestMapping in a spring controller.
First of all, because of the framework the project uses, there is a controller method mapped to the following url: "/{pageLabelOrId}"
Second, I have another controller method mapped to "/{pageName}.html". This works fine, meaning that if I try to access from browser "www.applicationUrl/something.html" this url if captured by the second method as is intended.
Now here is my problem. I must handle a somehow different but also similar url in a distinct method as follows: "/something-{parameter1}_{parameter2}_{parameter3}"
Trying to access "www.applicationUrl/something-1_2_3" will trigger the first controller: "/{pageLabelOrId}" instead of the desired one.
Handling this kind of url("/something-1_2_3") is a requirement and I cannot change it to something like "/something/{param1}/{param2}/{param3}" which I am sure it will work.
I have observed however, that writing a controller method mapped to "/something-{param}" will work and will capture my three parameters in one PathVariable(like "1_2_3") that I can parse afterwards by "_".
Does anyone have any idea of why does spring has this behavior and if I can somehow make it to work using three different path variables?
Spring 3.1+ uses a RequestMappingHandlerMapping to create RequestMappingInfo objects which map your controller handler methods to their corresponding #RequestMapping paths. When the DispatcherServlet receives a request, it uses the RequestMappingHandlerMapping again to determine which handler method should be used.
The way it is currently implemented, it finds all the registered RequestMappingInfo objects that match the request and then sorts them based on a number of rules, basically those defined in AntPathMatcher and AntPatternComparator.
You'll have to configure your RequestMappingHandlerMapping bean to use a custom PathMatcher with your own rules for comparing.
How you do this depends on how you are doing your configuration. If you use a #Configuration class, you can do
#Configuration
public class WebConfig extends WebMvcConfigurationSupport {
...
#Override
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
RequestMappingHandlerMapping mapping = super.requestMappingHandlerMapping();
mapping.setPathMatcher(pathMatcher()); // some PathMatcher bean
return mapping;
}
...
}
The RequestMappingInfo objects created by this RequestMappingHandlerMapping will internally use this PathMatcher. They will be sorted based on its Comparator.

Guice: how to get more than one #Provides for a type?

I'm working on a project and trying to bring two different 'data service' modules together into a web app (currently, the app is a desktop Swing app).
Each module has its own Guice (private) module. Each Guice module contains:
#Provides
#Inject
protected JPQLQuery provideJPQLQuery(EntityManager entityManager) {
return new JPAQuery(entityManager);
}
This is used later in the constructor of the classes that look things up from the db:
#Inject
public SomeClassThatLooksObjectsUpFromDatabase(Provider<JPQLQuery> queryProvider) {
this.queryProvider = queryProvider;
}
The 'queryProvider' is then able to execute queries.
Now, this works fine when only one of the Guice modules is installed, but once both are installed, I (predictably) get this error:
Unable to create binding for com.mysema.query.jpa.JPQLQuery. It was already configured on one or more child injectors or private modules
bound at ServiceOneGuiceModule.provideJPQLQuery()
bound at ServiceTwoGuiceModule.provideJPQLQuery()
Now, I understand why this is broken -- I'm saying that there's two Providers for the type JPQLQuery and Guice doesn't know which one to use.
Is there any way I can get Guice to separate these Providers? I would like to do this because each module has its own properly-configured Hibernate entities, and each has its own unique datasource (multiple databases in this project).
Ideally, it would involve something like somehow naming these providers and injecting them by their name (e.g. I could separately inject "ServiceOneJPQLQueryProvider" and "ServiceTwoJPQLQueryProvider"), but I haven't found any way of achieving anything like this.
(I suppose an alternative is to somehow configure Hibernate so it has all the different datasources it needs and then I'd only need one Provider for my queries, possibly, but that seems like a lot more work than what I'm describing above)
Have a look binding annotations, they're used to solve just the problem you've got.
They're recommended over using #Named because they are type-safe and will produce compilation errors and not runtime errors if you misspell them.
In short:
ServiceOne.java:
#BindingAnnotation #Target({ FIELD, PARAMETER, METHOD }) #Retention(RUNTIME)
public #interface ServiceOne {}
ServiceTwo.java:
#BindingAnnotation #Target({ FIELD, PARAMETER, METHOD }) #Retention(RUNTIME)
public #interface ServiceTwo {}
ServiceOneModule.java:
#Provides
#ServiceOne
#Inject
protected JPQLQuery provideJPQLQuery(EntityManager entityManager) {
return new JPAQuery(entityManager);
}
SomeClass.java:
#Inject
public SomeClassThatLooksObjectsUpFromDatabase(#ServiceOne Provider<JPQLQuery> queryProvider) {
this.queryProvider = queryProvider;
}
First of all, you're incorrect about #Named because providers are ubiquitous in Guice - in fact, when you create a binding like bind(...).to(...) or any other non-provider binding you're implicitly creating a provider. And it is just a shortcut for injecting providers when you inject objects directly - providers injection and direct injection are interchangeable in Guice (when you are not using special scopes like RequestScoped, but this is more like implementation detail of this shortcut). For example, even if you created #Provides method for JPQLQuery, you still can inject it directly, without a provider:
#Inject
public SomeClass(JPQLQuery query) {
...
}
Which approach to use depends on your requirements (do you need several fresh instances of JPQLQuery inside SomeClass methods?) and scopes in use (e.g. when scope of SomeClass is wider than that of JPQLQuery - for example, when SomeClass is singleton, and JPQLQuery is request scoped - sometimes provider usage is mandatory).
You're not getting what you want with #Named yet because you create #Named binding with #Provides, but still inject Provider<...> without annotation. It won't work because binding key consists both of injected type and (possibly absent) binding annotation, so if you have only bindings with assigned annotation but inject provider or type without annotation, Guice will fail. You should put #Named annotation onto the constructor parameter as well:
#Inject
public SomeClass(#Named("ServiceOne") Provider<JPQLQuery> queryProvider) {
...
}
This way it should work.
BTW, I strongly recommend against #Named. You'd better create separate binding annotation for each of your distinct binding for the same class, as described here. With custom annotations you won't have a chance to make a mistake in binding name when you inject it.
Also there is more advanced machinery for manipulating similar bindings. It is called private modules. However, you should rarely need it. It could be needed, for example, to create trees of objects which differ only in few bindings. This does not seem to be your case - binding annotations are your way to go.

Categories

Resources