NullPointerException on CrudRepository - java

I have created a repository but when I call my repository it gives a NullPointerException everytime. Can someone help me figure out why?
My repository
#Repository
public interface WorkflowObjectRepository extends CrudRepository<WorkflowObject, String> {
#Override
WorkflowObject findOne(String id);
#Override
void delete(WorkflowObject workflowObject);
#Override
void delete(String id);
#Override
WorkflowObject save(WorkflowObject workflowObject);
}
My Object
#Data
#Entity
#Table(name = "workflowobject")
public class WorkflowObject {
#GeneratedValue
#Column(name="id")
private String id;
#Column(name = "state_name")
private String stateName;
}
My test
public class Test {
#Autowired
static WorkflowObjectRepository subject;
public static void main(String[] args) {
final WorkflowObject obj = new WorkflowObject();
obj.setId("maha");
obj.setStateName("test");
subject.findOne("maha");
}
}
application.properties
spring.datasource.url=jdbc:postgresql://localhost:5432/vtr?
autoReconnect=true
spring.datasource.username=vtr
spring.datasource.password=vtr

The problem is you are trying to autowire a static data member
#Autowired
static WorkflowObjectRepository subject;
What happens in your case is static is getting initialized before the bean so you are autowiring on null, just remove the static and deal with it as instance variable.
repositories are singletones so no point of making them static

In order to work properly with #Autowired you need to keep in mind that spring scans annotations to allow automatically classes load.
If you need to #Autowired some class, the class Test needs to have some annotation, that tells to Spring Boot to find it.
Your Test class need to have #Component, #Service, #Controller, #Repository, etc. Otherwise #Autowired will not work because Spring Boot not know your class and will not process it.
You can find some explanation here

Related

Spring Boot Autowiring From Another Module

I am trying to establish connection between 3 modules in my project. When I try to reach my object with #Autowired error shows up. I'll explain my scenario a little bit.
MODULES
All of these modules have been connected inside of pom.xml. Lets talk about my problem.
C -> ROUTE.JAVA
.
.
.
#Autowired
public CommuniticationRepository;
#Autowired
public Core core;
.
.
.
B -> CORE
public class Core {
private int id;
private String name;
private Date date;
public Core(int id, String name, Date date) {
this.id = id;
this.name = name;
this.date = date;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
ERROR
Field communicationRepositoryin com.demo.xyz.A.RestControllers.Route required
a bean of type 'com.demo.xyz.A.CommunicationRepository' that could not be
found.
Action:
Consider defining a bean of type 'com.demo.xyz.A.CommunicationRepository' in
your configuration.
A - > REPOSITORY.JAVA
#Component
#Repository
public interface CommunicationRepository extends CrudRepository<Communication, Date> {
List<Communication> findByDate(Date date);
void countByDate(Date date);
}
You should remove #Component and #Repository from CommunicationRepository if it is a spring data JPA repository.
You should define configurations in modules A and B.
#Configuration
#EnableJpaRepositories(basePackages ={"com.demo.xyz.A"})
#EntityScan(basePackages = {"com.demo.xyz.A"})
#ComponentScan(basePackages = {"com.demo.xyz.A"})
public class ConfigA {
}
// If you have no spring managed beans in B this is not needed
// If Core should be a spring managed bean, add #Component on top of it
#Configuration
#ComponentScan(basePackages = {"com.demo.xyz.B"})
public class ConfigB {
}
Then, in C, where you bootstrap the application, you should import the configurations for module A and module B. At this point, any beans from A and B will be available for autowiring in C.
#Configuration
#Import(value = {ConfigA.class, ConfigB.class})
public class ConfigC {
}
Basically if you want to use #Autowired annotation on top of any attribute and use it, Obviously there should be an initialized bean in the spring context to Autowire it to your usages. So here your problem is in your spring context, there is no such bean to autowire.
So the solution is you need to have those beans inside your spring context, there are multiple ways to get this done,
The classes that you need beans auto initialized inside the spring context as #Component
Ex :
#Component
public class Car{
or you can manually have a configuration file which returns such beans
Ex :
#Bean
public Car setCarBean(){
return new Car();
}
And this bean returning should be inside a #Configuration class.
please refer
Then if you are really sure that you have done with this, then correct #ComponentScan should work
EDIT
#SpringBootApplication
#ComponentScan(basePackages = { "com.demo.xyz.A", "com.demo.xyz.B"})
public class Application {
Try to add scanBasePackages in the Application class.
The default scan is for the package in which the Application class.
#SpringBootApplication(scanBasePackages = "com.demo.xyz")
public class Application {...}

Best practice for #Value fields, Lombok, and Constructor Injection?

I'm developing a Java Spring application. I have some fields in my application which are configured using a .yml config file. I would like to import those values using an #Value annotation on the fields in question. I would also like to use the best-practice of constructor injection rather than field injection, but I would like to write my constructor using Lombok rather than manually. Is there any way to do all these things at once? As an example, this doesn't work but is similar to what I want to do:
#AllArgsConstructor
public class my service {
#Value("${my.config.value}")
private String myField;
private Object myDependency;
...
}
In this case, what I want is Lombok to generate a constructor which sets only myDependency, and for myField to be read from my config file.
Thanks!
You need #RequiredArgsConstructor and mark myDependency as final. In this case, Lombok will generate a constructor based on 'required' final filed as argument, for example:
#RequiredArgsConstructor
#Service
public class MyService {
#Value("${my.config.value}")
private String myField;
private final MyComponent myComponent;
//...
}
That is equal the following:
#Service
public class MyService {
#Value("${my.config.value}")
private String myField;
private final MyComponent myComponent;
public MyService(MyComponent myComponent) { // <= implicit injection
this.myComponent = myComponent;
}
//...
}
Since here is only one constructor, Spring inject MyComponent without the explicit use of the #Autowired annotation.
Male sure you are using at least version 1.18.4 of Lombok. And that you have your desired annotation added to the lombok.config file.
lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Value
Here is your class:
#AllArgsConstructor(onConstructor = #__(#Autowired))
public class MyService{
#Value("${my.config.value}")
private String myField;
private Object myDependency;
}
And here is the lombok generated class:
public class MyService {
#Value("${my.config.value}")
private String myField;
private Object myDependency;
#Autowired
#Generated
public MyService(#Value("${my.config.value}") final String myField, final Object myDependency) {
this.myField = myField;
this.myDependency = myDependency;
}
PS: Make sure you have the lombok.config file under /src/main/java folder. I tried adding it to /src/main/resources and it did not work.
Response taken from here.

How to Map a Java Entity to Multiple MongoDB Collections in Spring Data?

Currently, we're looking for a solution to save the following User entity into multiple MongoDB collections at the same time (i.e. db_users and on db_users_legacy). Both collections are in the same database.
Please don't ask me the reason why I need to save in two collections. It is a business requirement.
#Document(collection = "db_users")
#Data
#NoArgsConstructor
#AllArgsConstructor
public class User {
#Id
private String id;
private String name;
private String website;
private String name;
private String email;
}
And my SpringBoot application configuration goes as;
#Configuration
public class ApplicationConfig {
#Bean
public MongoTemplate mongoTemplate(MongoDbFactory factory){
MongoTemplate template = new MongoTemplate(factory);
template.setWriteConcern(WriteConcern.ACKNOWLEDGED);
retu,rn template;
}
}
Currently my repository looks as this. And saving works perfectly fine. How can I same this document in two different collections?
#Repository
public class UserRepositoryImpl implements UserRepository {
private MongoTemplate mongoTemplate;
public UserRepositoryImpl(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
#Override
public void save(User user) {
mongoTemplate.save(user);
}
}
Can anyone suggest the best option to deal with this, please?
I suggest using MongoTemplate's the other overloaded save method.
#Override
public void save(User user) {
mongoTemplate.save(user, "db_users");
mongoTemplate.save(user, "db_users_legacy");
}
This can be used to save same object to multiple collections.
From docs,
You can customize this by providing a different collection name using the #Document annotation. You can also override the collection name by providing your own collection name as the last parameter for the selected MongoTemplate method calls.
So it doesn't matter the collection name specifically provided in #Document, you can always override it using MongoTemplate.

Spring #Autowired and #Qualifier [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
Is it auto detected with #Autowired?
Is it dependency injection by name when #Qualifier is used?
How can we do setter and constructor injection using these annotations?
You can use #Qualifier along with #Autowired. In fact spring will ask you explicitly select the bean if ambiguous bean type are found, in which case you should provide the qualifier
For Example in following case it is necessary provide a qualifier
#Component
#Qualifier("staff")
public Staff implements Person {}
#Component
#Qualifier("employee")
public Manager implements Person {}
#Component
public Payroll {
private Person person;
#Autowired
public Payroll(#Qualifier("employee") Person person){
this.person = person;
}
}
EDIT:
In Lombok 1.18.4 it is finally possible to avoid the boilerplate on constructor injection when you have #Qualifier, so now it is possible to do the following:
#Component
#Qualifier("staff")
public Staff implements Person {}
#Component
#Qualifier("employee")
public Manager implements Person {}
#Component
#RequiredArgsConstructor
public Payroll {
#Qualifier("employee") private final Person person;
}
provided you are using the new lombok.config rule copyableAnnotations (by placing the following in lombok.config in the root of your project):
# Copy the Qualifier annotation from the instance variables to the constructor
# see https://github.com/rzwitserloot/lombok/issues/745
lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier
This was recently introduced in latest lombok 1.18.4.
The blog post where the issue is discussed in detail
The original issue on github
And a small github project to see it in action
NOTE
If you are using field or setter injection then you have to place the #Autowired and #Qualifier on top of the field or setter function like below(any one of them will work)
public Payroll {
#Autowired #Qualifier("employee") private final Person person;
}
or
public Payroll {
private final Person person;
#Autowired
#Qualifier("employee")
public void setPerson(Person person) {
this.person = person;
}
}
If you are using constructor injection then the annotations should be placed on constructor, else the code would not work. Use it like below -
public Payroll {
private Person person;
#Autowired
public Payroll(#Qualifier("employee") Person person){
this.person = person;
}
}
The #Qualifier annotation is used to resolve the autowiring conflict, when there are multiple beans of same type.
The #Qualifier annotation can be used on any class annotated with #Component or on methods annotated with #Bean. This annotation can also be applied on constructor arguments or method parameters.
Ex:-
public interface Vehicle {
public void start();
public void stop();
}
There are two beans, Car and Bike implements Vehicle interface
#Component(value="car")
public class Car implements Vehicle {
#Override
public void start() {
System.out.println("Car started");
}
#Override
public void stop() {
System.out.println("Car stopped");
}
}
#Component(value="bike")
public class Bike implements Vehicle {
#Override
public void start() {
System.out.println("Bike started");
}
#Override
public void stop() {
System.out.println("Bike stopped");
}
}
Injecting Bike bean in VehicleService using #Autowired with #Qualifier annotation. If you didn't use #Qualifier, it will throw NoUniqueBeanDefinitionException.
#Component
public class VehicleService {
#Autowired
#Qualifier("bike")
private Vehicle vehicle;
public void service() {
vehicle.start();
vehicle.stop();
}
}
Reference:- #Qualifier annotation example
#Autowired to autowire(or search) by-type
#Qualifier to autowire(or search) by-name
Other alternate option for #Qualifier is #Primary
#Component
#Qualifier("beanname")
public class A{}
public class B{
//Constructor
#Autowired
public B(#Qualifier("beanname")A a){...} // you need to add #autowire also
//property
#Autowired
#Qualifier("beanname")
private A a;
}
//If you don't want to add the two annotations, we can use #Resource
public class B{
//property
#Resource(name="beanname")
private A a;
//Importing properties is very similar
#Value("${property.name}") //#Value know how to interpret ${}
private String name;
}
more about #value

Spring boot custom auto configuration for entities

I'm working on a Spring Boot project which consists of multiple smaller projects. They all share a common project which consists of helper classes and such. On this common project I'm trying to create a Service, Repository, Entity and a Controller which could be shared and selectively enabled along of all other projects (debug endpoints with persisted data, each project has a separate database).
I'm thinking the ideal solution for this is to create a configuration bean which should be defined in order to enable these features or something along those lines.
At the moment I have this setup. Common entity:
#MappedSuperclass
public class SomeEntity {
#Id
#GeneratedValue
protected Long id;
#Column(unique = true)
protected String name;
public SomeEntity() {
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
}
The service defining common methods:
public abstract class SomeEntityService<T extends SomeEntity> {
private final SomeRepository<T> someRepository;
public SomeEntityService(SomeRepository<T> someRepository) {
this.someRepository = someRepository;
}
public T getSomeEntity(String name) {
return someRepository.findByName(name);
}
public List<T> getSomeEntities() {
return someRepository.findAll();
}
public abstract void init();
}
Common controller:
#RestController
#RequestMapping(value = "/entities")
#ConditionalOnBean(value = SomeEntityService.class)
public class SomeController<T extends SomeEntity> {
private final SomeEntityService<T> someEntityService;
#Autowired
public SomeController(SomeEntityService<T> someEntityService) {
this.someEntityService = someEntityService;
}
#RequestMapping(method = RequestMethod.GET)
public List<T> getSomeEntities() {
return someEntityService.getSomeEntities();
}
#RequestMapping(value = "/{name}", method = RequestMethod.GET)
public T getSomeEntity(#PathVariable String name) {
return someEntityService.getSomeEntity(name);
}
}
Common repository:
#NoRepositoryBean
public interface SomeRepository<T extends SomeEntity> extends JpaRepository<T, Long>, JpaSpecificationExecutor<T> {
T findByName(String name);
}
The full project can be found here.
Now in this example, if I implement SomeService, SomeEntity and SomeRepository, the controller bean gets created (notice the #ConditionalOnBean annotation on the controller) and everything works fine. However I do not want to redefine the entity and repository as all the needed implementation is already there, however I cannot find any documentation on how to disable the creation of these beans based on some conditions. So the questions would be:
How can I disable the creation of specific #Entity annotated classes?
How can I do the same for #Repository annotated classes?
Is there a better way of doing this sort of thing?
Edit:
A more concrete question would be - how could I exclude selected entities from scanning based on some condition, is it possible to do this in spring?
For example, create a set of entities only is some specific bean is created or some property in application.properties file is defined.
What about using #ConditionalOnProperty and configuring it through properties files?
This article has the following to say:
In Spring Boot, you can use the #ConditionalOnProperty annotation to enable or disable a particular bean based on the presence of a property. This is very useful if you want to provide optional features to your microservice.

Categories