I cant #Autowired a DatastoreRepository bean (Goolge cloud datastore) - java

I'm trying to create a bean of the DatastoreRepository class but I get the following error Iam using spring-boot 2.1.3
Description:
The bean 'bookRepository', defined in null, could not be registered. A bean with that name has already been defined in null and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
this is my project structure I have the Application main run class in a root package like this
com.mycompany.project
--Application.java
--controller
--domain
--repository
The class with the #SpringBootApplication is in the root package
here is my repository class
import org.springframework.cloud.gcp.data.datastore.repository.DatastoreRepository;
public interface BookRepository extends DatastoreRepository<Book, Long>{
}
Here is my domain class
import org.springframework.cloud.gcp.data.datastore.core.mapping.Entity;
import org.springframework.data.annotation.Id;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
#Entity(name = "books")
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Book {
#Id
Long id;
String title;
}
and here is my controller class
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class AppUserController {
#Autowired
BookRepository bookRepository;
#GetMapping("/booksave")
public String helloworld() {
bookRepository.save(new Book(3L, "author"));
return "book saved";
}
}
and here is my Application class
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

I think the problem is the way you are using the annotation, try changing the Injection to the Constructor, something like:
#RestController
public class AppUserController {
private BookRepository bookRepository;
#Autowired
public AppUserController (
BookRepository bookRepository){
this.bookRepository= bookRepository;
}
#GetMapping("/booksave")
public String helloworld() {
bookRepository.save(new Book(3L, "author"));
return "book saved";
}
}
Source to understand it: Spring #Autowire on Properties vs Constructor

Add this annotation, #EnableDatastoreRepositories, to your Application.java

How about using Spring data rest :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
you won't need to code controllers
import org.springframework.cloud.gcp.data.datastore.repository.DatastoreRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
#RepositoryRestResource(collectionResourceRel = "xxxxxs", path = "xxxx")
public interface XXXXXRepository extends DatastoreRepository<XXXXX, String>
swagger config !!!
#Configuration
#EnableSwagger2WebMvc
#Import(SpringDataRestConfiguration.class)
public class SwaggerConfig {

Related

Force autowire repository by name and not by type

I am trying to create a java + spring library (a seperate, reusable, application independent jar file) and use it in the application.
I show you a non-working example, that is already suitable to demonstrate my problem.
My problem is, that i have difficulties to autowire a repository by name and not by type.
The jar file logic is implemented here in one file called Library
package com.example;
import javax.persistence.MappedSuperclass;
import javax.persistence.OneToOne;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.Repository;
import org.springframework.stereotype.Service;
public class Library {
#MappedSuperclass
public static class ChildEntity {
public String childAttribute;
}
#MappedSuperclass
public static class RootEntity<T extends ChildEntity> {
public String rootAttribute;
#OneToOne
public T childEntity;
}
#Service
public static class RootEntityService<T extends ChildEntity> {
#Autowired
#Qualifier(Library.REPOSITORY_BEAN_NAME)
private RootRepository<T> repository;
public RootEntity<T> findMyEntity() {
return this.repository.findByChildEntity();
}
}
#NoRepositoryBean
public static interface RootRepository<T extends ChildEntity> extends Repository<T, Long> {
public RootEntity<T> findByChildEntity();
}
public final static String REPOSITORY_BEAN_NAME = "entityRepository";
}
As you can see i have a RootEntity and a ChildEntity with a OneToOne relation.
The RootRepository is defined as #NoRepositoryBean, since Repository cannot have generic parameters.
The RootService is referencing for the RootRepository and i am trying to autowire by name and not type - using the #Qualifier annotation.
Here comes the application itself:
package com.example;
import javax.persistence.Entity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.stereotype.Repository;
import com.example.Library.ChildEntity;
import com.example.Library.RootEntity;
import com.example.Library.RootEntityService;
import com.example.Library.RootRepository;
public class Application implements ApplicationRunner {
#Entity
public static class RealChildEntity extends ChildEntity {
public String realChildAttribute;
}
#Entity
public static class RealRootEntity extends RootEntity<RealChildEntity> {
}
#Repository(Library.REPOSITORY_BEAN_NAME)
public static interface RealRootRepository extends RootRepository<RealChildEntity> {
}
public static void main(final String[] args) throws Exception {
SpringApplication application;
application = new SpringApplication(ApplicationConfig.class);
application.setWebApplicationType(WebApplicationType.NONE);
application.run(args);
}
#Autowired
private RootEntityService<RealChildEntity> rootEntityService;
#Override
public void run(final ApplicationArguments args) throws Exception {
this.rootEntityService.findMyEntity();
}
}
The RealChildEntity has an application specific attribute.
I define the RealRootRepository to be a real repository, without generic parameters. I have also defined a bean name for this component to refer to.
I also have an ApplicationConfig class to define the service bean and the repo:
package com.example;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import com.example.Library.ChildEntity;
import com.example.Library.RootEntityService;
#Configuration
#EnableJpaRepositories(basePackageClasses = { Application.class })
public class ApplicationConfig {
#Bean(Library.REPOSITORY_BEAN_NAME)
public <T extends ChildEntity> RootEntityService<T> entityService() {
return new RootEntityService<T>();
}
}
If i execute this application, than spring gives me the following error:
***************************
APPLICATION FAILED TO START
***************************
Description:
Field repository in com.example.Library$RootEntityService required a bean of type 'com.example.Library$RootRepository' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
- #org.springframework.beans.factory.annotation.Qualifier(value="entityRepository")
Spring tells me, that RootEntityService required a bean of type. Why by type?
I want a repository by name
What am i doing wrong?
How can i have a library service without extending it just because of the repository;
Thanks for your help in advance

Spring MVC - inject map from yaml file

I have a configuration YAML (application.yml) file which contains location data:
locations:
countries:
PL: Poland
DE: Germany
UK: UK
RU: Russia
I would like to load it so it will be available in the html select field.
I have created a following class:
package eu.test.springdemo.model;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.Map;
#ConfigurationProperties(prefix = "locations")
public class CountryOptions {
private Map<String, String> countries;
public Map<String, String> getCountries() {
return countries;
}
public void setCountries(Map<String, String> countries) {
this.countries = countries;
}
}
Then I inject CountryOptions to Controller by #Autowire. However the list of countries is empty in controller.
Configuration of app is provided by class containing following annotations:
#Configuration
#EnableWebMvc
#EnableConfigurationProperties(CountryOptions.class)
#ComponentScan(basePackages="eu.test.springdemo")
public class DemoAppConfig implements WebMvcConfigurer {
Controller code
package eu.test.springdemo.mvc;
import eu.test.springdemo.model.CountryOptions;
import eu.test.springdemo.model.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
#Controller
#RequestMapping("/")
public class HelloController {
#Autowired
CountryOptions countryOptions;
#GetMapping("/")
public String showPage() {
return "main-menu";
}
#GetMapping("/showForm")
public String showForm(Model model) {
model.addAttribute("student", new Student());
model.addAttribute("countries", countryOptions.getCountries());
return "helloworld-form";
}
}
So - any ideas why list of countries is not created from yaml file?
#ConfigurationProperties is a Spring Boot feature and will not be bound to the application.yml if you aren't using it. The best solution is usually to convert to Boot.

NullPointerException: null while trying to do a MongoDB FindByID

So i'm trying to connect java spring to mongoDB and using a findById, but it always gives the null pointer error.
2020-08-04 13:54:01.893 ERROR 8312 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
java.lang.NullPointerException: null
at pt.project.ProvaConceito_BackEnd.mongoDB.UserService.findById(UserService.java:29) ~[classes/:na]
at pt.project.ProvaConceito_BackEnd.mongoDB.mongoDBService.getUserByID(mongoDBService.java:19) ~[classes/:na]
The structure of this project is:
Java
MongoDB
mongoDBService
UserService
Pojos
User
Repositories
UserRepository
I'm gonna share the code I have right now:
mongoDBService
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import pt.project.ProvaConceito_BackEnd.pojos.User;
#RestController
#CrossOrigin(origins="http://localhost:4200")
public class mongoDBService {
UserService userService = new UserService();
#RequestMapping("/concept/user")
public User getUserByID(Integer id) {
return userService.findById(1);
}
}
UserService
package pt.project.ProvaConceito_BackEnd.mongoDB;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import pt.project.ProvaConceito_BackEnd.pojos.User;
import pt.project.ProvaConceito_BackEnd.repositories.UserRepository;
import java.util.List;
#Service
public class UserService {
#Autowired(required = false)
private UserRepository userRepository;
public void save(String nome, int idade, String morada) {
userRepository.save(new User(nome, idade, morada));
}
public List<User> findAll() {
return userRepository.findAll();
}
public long count() {
return userRepository.count();
}
public User findById(Integer id) {
return userRepository.findById(id).orElse(null);
}
public void delete(Integer id) {
userRepository.deleteById(id);
}
}
Users (Pojo)
package pt.project.ProvaConceito_BackEnd.pojos;
import lombok.Getter;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
#Document(collection = "Users")
#Getter
public class User {
#Id
private Integer id;
private String nome;
private int idade;
private String morada;
public User(String nome, int idade, String morada) {
this.nome = nome;
this.idade = idade;
this.morada = morada;
}
}
UserRepository
package pt.project.ProvaConceito_BackEnd.repositories;
import org.springframework.data.mongodb.repository.MongoRepository;
import pt.project.ProvaConceito_BackEnd.pojos.User;
public interface UserRepository extends MongoRepository<User, Integer> {
}
What am I doing wrong here? I think the problem is on mongoDBService...
in this line:
UserService userService = new UserService();
Because I think that it's not being injected, but I don't know how to solve that...
EDIT 1
I have my main class inside pt.project.ProvaConceito_BackEnd:
ProvaConceitoBackEndApplication
package pt.project.ProvaConceito_BackEnd;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class ProvaConceitoBackEndApplication {
public static void main(String[] args) {
SpringApplication.run(ProvaConceitoBackEndApplication.class, args);
}
}
Do not use new to create object that way because spring will not have any knowledge of that object and will not be able to inject it.
Since you have already annotated the UserService with #service you should use #Autowired annotation
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import pt.project.ProvaConceito_BackEnd.pojos.User;
#RestController
#CrossOrigin(origins="http://localhost:4200")
public class mongoDBService {
#Autowired
private UserService userService;
#RequestMapping("/baieuropa/user")
public User getUserByID(Integer id) {
return userService.findById(1);
}
}
Also annotate the UserRepository class with #Repository
package pt.project.ProvaConceito_BackEnd.repositories;
import org.springframework.data.mongodb.repository.MongoRepository;
import pt.project.ProvaConceito_BackEnd.pojos.User;
#Repository
public interface UserRepository extends MongoRepository<User, Integer> {
}
Remove required = false from UserService class
Make sure to have a class with #SpringBootApplication annotation in pt.project.ProvaConceito_BackEnd package.
You need to update your repository and User.class to have an ID type of string instead of Integer. This is required for mongo repositories. May not completely solve your problem but will be a step in the right direction
#Repository
public interface UserRepository extends MongoRepository<User, String> {
}
I would follow the suggestions of other contributors to remove the "new" keyword from your mongoDBService and use the #Repository annotation too.
Autowiring only works if all components that it relies on are autowired too. So in your case because the mongoDBService uses new for the UserService then it expects the Repository to use "new" too. You should instead autowire at all levels and remove the required=false from the autowiring in the UserService.
The repository requires the #Repository annotation otherwise when Spring does its component scan the repository wont be picked up without it. #Repository #RestController etc are all just stereotypes for #Component with varying degrees of additional functionality

Field in required a bean of type that could not be found consider defining a bean of type in your configuration

I'm getting the following error when trying to run my app:
Field edao in com.alon.service.EmployeeServiceImpl required a bean of
type 'com.alon.repository.EmployeeRepository' that could not be found.
The injection point has the following annotations:
#org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type
'com.alon.repository.EmployeeRepository' in your configuration.
Project structure:
EmployeeRepository:
package com.alon.repository;
import com.alon.model.Employee;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
public interface EmployeeRepository {
List<Employee> findByDesignation(String designation);
void saveAll(List<Employee> employees);
Iterable<Employee> findAll();
}
EmployeeServiceImpl:
package com.alon.service;
import com.alon.model.Employee;
import com.alon.repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class EmployeeServiceImpl implements EmployeeService {
#Autowired
private EmployeeRepository edao;
#Override
public void saveEmployee(List<Employee> employees) {
edao.saveAll(employees);
}
#Override
public Iterable<Employee> findAllEmployees() {
return edao.findAll();
}
#Override
public List<Employee> findByDesignation(String designation) {
return edao.findByDesignation(designation);
}
}
MyApplication:
package com.alon;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class MyApplicataion {
public static void main(String[] args) {
SpringApplication.run(MyApplicataion.class, args);
}
}
As you have added spring-boot tag I guess you are using sprig data jpa. Your repository interfaces should extend org.springframework.data.repository.Repository (a marker interface) or one of its sub interfaces (usually org.springframework.data.repository.CrudRepository) for instructing spring to provide a runtime implementation of your repository, if any of those interfaces are not extened you'll get
bean of type 'com.alon.repository.EmployeeRepository' that could not
be found.
I assume you try to use spring data JPA. What you can check / debug is:
Is JpaRepositoriesAutoConfiguration executed? You can see this in the start up log in the debug log level
Does something change if you addionally add #EnableJpaRepositories with the corresponding basepackages.
Add #ComponentScan with the corresponding packages, normally #SpringBootApplication should do it, but just in case.
you can also check the autconfig documentation: https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-auto-configuration.html
EDIT: see comment from #ali4j: I did not see that it is the generic spring Repository interface and not the spring data interface
regards,WiPu

Consider defining a bean of type 'com.gisapp.gisapp.dao.IUserDAO' in your configuration

When I start my spring-boot app I have this message:
APPLICATION FAILED TO START
Description:
Field userDAO in com.gisapp.services.impl.UserService required a bean
of type 'com.gisapp.gisapp.dao.IUserDAO' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.gisapp.gisapp.dao.IUserDAO' in
your configuration.
What I have read in other post related to this problem is that I have to configure the annotation #ComponentScan, but it does not work
MAIN CLASS:
package com.gisapp.gisapp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication
#ComponentScan("com.gisapp")
public class GisappApplication {
public static void main(String[] args) {
SpringApplication.run(GisappApplication.class, args);
}
}
SERVICE CLASS
#Service
public class UserService implements IUserService {
#Autowired
IUserDAO userDAO;
#Override
#Transactional(readOnly=true)
public Object login() {
return userDAO.login();
}
}
- UserDAO
package com.gisapp.gisapp.dao.impl;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import com.gisapp.gisapp.dao.IUserDAO;
import com.gisapp.models.entity.User;
public class UserDAO implements IUserDAO{
#Override
public Object login() {
StringBuilder query = new StringBuilder();
query.append("SELECT * FROM User");
EntityManager em = null;
Query q = em.createNativeQuery(query.toString());
List<User> result=q.getResultList();
return result;
}
}
IUserDAO should be recognised as a bean and the app should run
1) Add a #Repository annotation in order for the DAO to be loaded as a bean into the spring context:
#Repository
public class UserDAO implements IUserDAO{
2) Just on the side.. you should most likely inject the EntityManager in it also:
#PersistenceContext
private EntityManager em;

Categories

Resources