#Nullable in Spring 5 is annotated with #Nonnull - spring

I just updated my project to use Spring Boot 2.0.3 with Spring Framework 5.0.7.
And now I see that some parameters in methods of MessageSource are annotated with Spring's shiny new #Nullable annotation. But due to this annotation, IDEA 14 says that the appropriate parameters cannot be null (SURPRISE!).
As I understand that's due to the fact that #Nullable is annotated with #Nonnull:
#Nonnull(
when = When.MAYBE
)
What was the reason to mark annotation with a logically opposite one?

As explained by #StephanHerrmann, it's related to the original JSR.
So the idea is that null value is allowed in some cases - just to make code self-documented.
Similar approach is actually used in javax.annotation.Nullable:
#Documented
#TypeQualifierNickname
#Nonnull(when = When.UNKNOWN)
#Retention(RetentionPolicy.RUNTIME)
public #interface Nullable {
}
In latest IDEA versions this annotation is supported (or WILL be supported) out of the box.
To fix IDEA warning in older versions you just need to add the Spring's annotation manually.

Related

SpringMVC global setting for ignoring unknown properties during deserialization

Spring Boot sets "spring.jackson.deserialization.fail-on-unknown-properties=false" by default. I have a library that works fine in Spring Boot, but when used in an existing SpringMVC app it throws "Unrecognized field, not marked as ignorable". Is there some comparable global setting for SpringMVC I can set in the config or otherwise?
edit: spring webmvc version 3.2.15.RELEASE
You can annotate the mapped classes with
#JsonIgnoreProperties(ignoreUnknown = true)
or create add the following configuration to the ObjectMapper as follows:
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
You can follow two method that I have mention in this answer. If I'm not wrong either one will work for you. (But method 1 won't work if your clinet class does not have a no-arg default constructor)

What class implements the spring framework Autowired

I downloaded the spring-framework project, because I want to see how #Autowired is implemented.
So, I got to this file, which is an interface.
But when I want in Intellij to go to its implementation, no implementations are found.
So is this interface not implemented?
Then where is the code for #Autowired?
Well, this is not an interface it is actually an annotation.
In java #inteface is used to create an annotation.
Once the annotation is created, you can use that annotation on fields, classes, methods (based on what is specified in #Target of the annotation definition.
Spring does package scanning and finds all the things which are using a particular annotation and does the required processing.
Use this article to undestand more in How an annotation is created, used and the how the annotation processor finds and processes the annotation.
#Autowired doesn't really have much code, so to speak. It's just an annotation which is a Java type of interface that provides instructions to other parts of the codebase.
#Autowired is only an annotation or you can say a "marker". Spring use reflection to identify annotation and do something about that annotated thing. For example with #Autowired, when spring found it, spring will inject the annotated property with eligible bean.

Spring Boot JPA CrudRepository

I'm working with Spring Boot + Spring Data JPA and facing this problem when trying to inject a class that extends CrudRepository:
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'topicRepository': Could not resolve
matching constructor (hint: specify index/type/name arguments for
simple parameters to avoid type ambiguities)
Repository Class:
public interface TopicRepository extends CrudRepository<Topic, Integer> {}
Service Class:
#Service
public class TopicService {
#Autowired
private TopicRepository topicRepository;
}
Any suggestions?
I was having the same issue, and I fixed it by switching Spring Boot versions. Changing the Spring Data JPA versions did nothing (this is where I assumed the bug would be), so I think there is a bug in Spring Boot version 1.5.1. I switched back to version 1.4.3 and the error was gone. I didn't try subsequent/different versions, so you may just have to experiment with your dependencies and their versions.
For the record, you can have your service class annotated with #Repository, it shouldn't make any difference. I've been setting these apps up the same way using the service/dao pattern, and it has never been too picky with the annotations. Hopefully this may help others whose Spring Boot development flow suddenly throws an error!
Which versions of spring-data-commons and spring-data-jpa are you using. I just ran into this using spring-data-commons 1.13.x with spring-data-jpa 1.10.x. Upgrading spring-data-jpa to 1.11.x fixed the issue for me.
I too had the same issue after updating Spring Boot to 1.5.4.
I am also using spring-data-envers, which was at version 1.0.4. Upgrading to 1.4.1 solved the problem.
I hope it helps someone :)
Make sure:
1) TopicRepository is annotated with #Repository.
2) You have the scanning packages configured:
<jpa:repositories base-package="mypkg.repositories"></jpa:repositories>
Had the same issue on 1.5.2. Upgrading to 1.5.5 solved the problem.
You can use Applicationcontext to inject repository to this reference topicRepository..
You just declare applicationcontext in #rest controller class
Same like topicRepository by using annotation. Then you pass this to the service class which should take parms through constructor.
Ex-
public TopicService(Applicationcontext ctx) {this.topicRepository =context.getBean(TopicRepository.class);
}

Spring injects dependencies in constructor without #Autowired annotation

I'm experimenting with examples from this official Spring tutorials and there is a dependency on this code:
https://github.com/spring-guides/gs-async-method/tree/master/complete
If you look at the code on AppRunner.java class, I have 2 questions:
When server is starting, if I put a breakpoint in this class's constructor, seems like in the constructor, the GitHubLookupService is provided by spring, using the #Service bean that was configured. BUT, there was no #Autowired annotation on the constructor, so how in the world this constructor get called with the right dependency? It was supposed to be null.
Is it an automatic assumption of Spring Boot?
Does Spring see "private field + constructor argument, and it assumes it should look for an appropriate bean?
Is it Spring Framework or Spring boot?
Am I missing something?
As I remember, it was mendatory to provide default constructor to beans / service etc. How come this class (AppRunner) doesn't have a default constructor?
How does Spring knows that it should run the constructor with the argument?
Is it because it is the only constructor?
Starting with Spring 4.3, if a class, which is configured as a Spring bean, has only one constructor, the #Autowired annotation can be omitted and Spring will use that constructor and inject all necessary dependencies.
Regarding the default constructor: You either need the default constructor, a constructor with the #Autowired annotation when you have multiple constructors, or only one constructor in your class with or without the #Autowired annotation.
Read the #Autowired chapter from the official Spring documentation for more information.
Think of it this way... Suppose you have the following component:
#Component
public class FooService {
public FooService(Bar bar) { /*whatever*/ }
}
When Spring is scanning this class, it wants to know how it should go about constructing an instance. It's using reflection so it can get a list of all of the constructors at runtime.
In this case, it is completely unambiguous how Spring must construct this instance. There's only one constructor so there is no decision to be made, and no ambiguity at all.
If you add #Autowired here, you are not narrowing anything down, and you are not giving Spring any extra information to help make its decision - its decision is already made because there is only one candidate.
And so, as a convenience, the Spring team decided #Autowired should be optional. Since its not helping the Spring framework to make a decision, its presence is just noise.
If your component has multiple constructors then you can use #Autowired on one of them to tell Spring "use this one, not that one".

#Qualifier and #Resource doesn't work when running test case under Spring test framework

I have a test case which has a dependency of 'ticketDao', like below:
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Qualifier;
public class LfnSaleCancellationIntegrationTest extends BaseIntegrationTest {
//#Resource(name = "baseTicketDao")
private BaseTicketDao ticketDao;
....
public void setTicketDao(#Qualifier("baseTicketDao") BaseTicketDao ticketDao) {
this.ticketDao = ticketDao;
}
}
and BaseIntegrationTest extends from spring test framework's AbstractJpaTests, Spring is v3.0.5
When run this test case, I got a similar exception:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:
No unique bean of type [com.mpos.lottery.te.gamespec.sale.dao.BaseTicketDao]
is defined: expected single matching bean but found 2:
[baseTicketDao, extraballTicketDao]
My project has evolved a long time, in fact when I encountered this exception at the first time, #Qualifier solved it. Till today this project has changed much, but I really have no idea why #Qaulifier and #Resource don't work any more.
And if i remove the dependency of 'ticketDao', the test case will pass. I am wondering whether there are some change of spring configuration cause this exception? or ... i have googled much, but seem no other people ever faced such a problem, pls give your comments, thanks very much!
You are using AbstractJPATests which is part of old spring test framework and (indirect) subclass of AbstractDependencyInjectionSpringContextTests. By default the injection is not annotation based but it discovers setters and fields and attempts injection by type. It would be recommended to switch to newer annotation based tests, refer to spring documentation for details.
As a workaround try to change autowire mode. Call it in test constructor as this.setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME), rename your field to baseTicketDao and remove setter.
I knew the reason. In my new project, there are a statement of context:component-scan in spring configuration file, which will register 4 BeanPostProcessors by default:
AutowiredAnnotationBeanPostProcessor(#Autowired)
RequiredAnnotationBeanPostProcessor(#Require)
CommonAnnotationBeanPostProcessor(JSR-250 annotations, #Resource, #PostConstruct etc, #WebServiceRef )
PersistenceAnnotationBeanPostProcessor(#PersistenceUnit and #PersistenceContext)
While in my old project, only the default BeanPostProcessor(internalAutoProxyCreator) has been registered. My understanding is AutowiredAnnotationBeanPostProcessor will always wire by type. Anyway if remove context:component-scan, my test case can pass now.
In fact i have migrate all my test cases to spring test context framework now, and context:component-scan must be stated, otherwise #Autowired, #Resource etc annotation will be ignored, and you will get a great many of NullPointerException of those automaticaly injected dependencies.
NOTE: <context:annotation-config/> will register those 4 BeanPostProcessors too.

Resources