I'm trying to get a CrudRepository to work:
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.codynx.itemizer.model.Task;
#Repository
public interface TaskMysqlRepository extends CrudRepository<Task, Integer> {
}
used here:
import java.sql.ResultSet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.codynx.itemizer.model.Task;
import com.codynx.itemizer.repository.TaskMysqlRepository;
#Service
public class TaskMysqlService {
public ResultSet resultSet = null;
private Iterable<Task> tasks;
#Autowired
private TaskMysqlRepository taskMysqlRepository;
public TaskMysqlService() {
}
public Iterable<Task> getTasks(){
return taskMysqlRepository.findAll();
}
}
But I get the error message:
required a bean of type 'com.codynx.itemizer.repository.TaskMysqlRepository' that could not be found
The repo is there and has the correct annotation. What am I doing wrong?
Here is also the Task Type:
[...]
#AllArgsConstructor
#NoArgsConstructor
#Data
#Builder
public class Task {
#JsonProperty(access = Access.READ_ONLY)
#Id
private String id;
#Version
private Long version;
private LocalDateTime start;
private LocalDateTime due;
private boolean done;
private String name;
private Integer parent_id;
}
Is it because of some type missmatch? I mean the repo is there...
May be in your case due to package structure, autoconfiguration is not happening.
Try adding #EnableJpaRepositories and #EntityScan and mention the packages.
#SpringBootApplication
#EntityScan(basePackages = {"com.entities.package"}) //your entities package goes here
#EnableJpaRepositories(basePackages = {"com.repositories.package"})//your repository package goes here
public class SpringBootDataJpaApplication
{
public static void main(String[] args)
{
SpringApplication.run(SpringBootDataJpaApplication.class, args);
}
}
Related
I'm building a Spring Boot app using CosmosDB as my database. All functions work (creating an item, updating one, get all, get by id,...), apart from delete functions. They don't do anything and since their output is void, it doesn't give me any logs either.
The DAO class:
package projects.trashcanapplication.trashcan.dao;
import com.azure.spring.data.cosmos.core.mapping.Container;
import com.azure.spring.data.cosmos.core.mapping.GeneratedValue;
import com.azure.spring.data.cosmos.core.mapping.PartitionKey;
import org.springframework.data.annotation.Id;
import projects.trashcanapplication.trashcan.models.Address;
import projects.trashcanapplication.trashcan.models.FillStatus;
#Container(containerName = "trashcanData")
public class TrashcanDao{
#GeneratedValue
private String attachments;
private FillStatus fillStatus;
#GeneratedValue
private String rid;
private Address address;
#Id
#PartitionKey
#GeneratedValue
private String id;
#GeneratedValue
private String self;
#GeneratedValue
private String etag;
#GeneratedValue
private int ts;
public TrashcanDao(Address address, FillStatus fillStatus) {
this.fillStatus = fillStatus;
this.address = address;
}
public String getAttachments(){
return attachments;
}
public FillStatus getFillStatus(){
return fillStatus;
}
public String getRid(){
return rid;
}
public Address getAddress(){
return address;
}
public String getId(){
return id;
}
public String getSelf(){
return self;
}
public String getEtag(){
return etag;
}
public int getTs(){
return ts;
}
}
The repository
package projects.trashcanapplication.trashcan.repositories;
import com.azure.spring.data.cosmos.repository.ReactiveCosmosRepository;
import projects.trashcanapplication.trashcan.dao.TrashcanDao;
public interface TrashcanRepository extends ReactiveCosmosRepository<TrashcanDao, String> {
}
The service calling the repository
package projects.trashcanapplication.trashcan.services;
import com.azure.cosmos.models.PartitionKey;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import projects.trashcanapplication.trashcan.dao.TrashcanDao;
import projects.trashcanapplication.trashcan.models.Trashcan;
import projects.trashcanapplication.trashcan.repositories.TrashcanRepository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
#Slf4j
#Service
#AllArgsConstructor
public class TrashcanServiceImpl implements TrashcanService {
private final TrashcanRepository trashcanRepository;
private final TrashcanMapper trashcanMapper;
public Flux<Trashcan> getAllTrashcans() {
return trashcanRepository.findAll().map(trashcanMapper::fromDaoToTrashcan);
}
public Mono<Trashcan> getTrashcanById(String id) {
return trashcanRepository.findById(id).map(trashcanMapper::fromDaoToTrashcan);
}
public String createTrashcan(Trashcan trashcan) {
TrashcanDao saveTrashcan = trashcanMapper.fromTrashcanToDao(trashcan);
trashcanRepository.save(saveTrashcan).subscribe();
return saveTrashcan.getId();
}
public void deleteTrashcan(String id) {
trashcanRepository.deleteById(id, new PartitionKey(id));
log.info(String.format("Deleted trashcan %s", id));
}
}
I have a dataloader temporarily set up to populate my DB with an item upon running the app. The deleteAll() function doesn't work here either.
package projects.trashcanapplication.trashcan.services;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import projects.trashcanapplication.trashcan.dao.TrashcanDao;
import projects.trashcanapplication.trashcan.models.Address;
import projects.trashcanapplication.trashcan.models.FillStatus;
import projects.trashcanapplication.trashcan.repositories.TrashcanRepository;
import javax.annotation.PostConstruct;
#Slf4j
#Component
#AllArgsConstructor
public class DataLoader {
private final TrashcanRepository trashcanRepository;
#PostConstruct
void loadData() {
Address address1 = new Address("Begijnendijk", "3130", "Liersesteenweg", "181");
trashcanRepository.deleteAll();
trashcanRepository.save(new TrashcanDao(address1, FillStatus.EMPTY))
.flatMap(trashcanRepository::save)
.thenMany(trashcanRepository.findAll())
.subscribe(trashcan -> log.info(trashcan.getId().toString()))
;
}
}
You're not subscribing anywhere, so the reactive stream isn't executed.
You could solve that by subscribing manually:
trashcanRepository.deleteAll().subscribe()
However, this is not a good practice, and certainly not in your DataLoader as you can't guarantee the order in which the save/delete-logic is executed (maybe the TrashcanDao is saved before you delete everything).
To solve this, you should create a proper reactive stream:
trashcanRepository
.deleteAll()
.then(trashcanRepository.save(new TrashcanDao(address1, FillStatus.EMPTY)))
.thenMany(trashcanRepository.findAll())
// Your previous subscribe() shouldn't compile since it should contain List<TrashcanDao>
.subscribe(trashcans -> log.info(trashcans.size()));
The goal of this method is to provide functionality to a service layer method that will find all songs within a PostgreSQL database. I have implemented an interface "SongServiceInterface" in the service layer and in the event I utilize this SongService via instantiation in the main method or even by sending Http Requests via "/songs" endpoint, I receive this error:
Caused by: java.lang.NullPointerException: Cannot invoke "com.techm.react.Wasteland.repository.SongRepo.findAll()" because "this.songRepo" is null.
Please note upon startup the application will persist the objects to database, but using endpoints or methods within this repo/service cause null field error.
I can provide the code below:
Model
package com.techm.react.Wasteland.models;
import lombok.*;
import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import javax.persistence.*;
import java.sql.Time;
#Entity
#Table(name = "song")
#NoArgsConstructor
#AllArgsConstructor
#Getter #Setter
#EqualsAndHashCode
#ToString
public class Song {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "title")
private String title;
#JoinColumn(name = "album")
#ManyToOne
#OnDelete(action = OnDeleteAction.CASCADE)
private Album album;
#Column(name = "artists")
private String artists;
#Column(name = "track")
private int track;
#Column(name = "track_length")
private Time length;
}
DTO
package com.techm.react.Wasteland.dto;
import com.techm.react.Wasteland.models.Album;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.sql.Time;
#Data
#NoArgsConstructor
#AllArgsConstructor
public class SongDTO {
private String title;
private AlbumDTO album;
private String artists;
private int track;
private Time length;
}
Repo
package com.techm.react.Wasteland.repository;
import com.techm.react.Wasteland.models.Song;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
public interface SongRepo extends JpaRepository<Song, Integer> {
public abstract List<Song> findAll();
public abstract List<Song> findByArtist();
public abstract Song findByTrack();
}
Service
package com.techm.react.Wasteland.service;
import com.techm.react.Wasteland.dto.SongDTO;
import com.techm.react.Wasteland.models.Song;
import com.techm.react.Wasteland.repository.SongRepo;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
#Service #Configurable
public class SongService implements SongServiceInterface{
#Autowired
SongRepo songRepo;
#Autowired
private ModelMapper modelMapper;
public List<SongDTO> findAllSongs() {
List<SongDTO> songDTOS = new ArrayList<>();
List<Song> songs = songRepo.findAll();
for(Song s: songs) {
songDTOS.add(modelMapper.map(s, SongDTO.class));
}
return songDTOS;
}
public SongDTO getSongByTitle(String title) throws NoSuchFieldException {
SongDTO song = new SongDTO();
if(title == song.getTitle()){
return song;
}
else throw new NoSuchFieldException("The song by that title does not exist");
}
public SongDTO findByTrack(int track) {
SongDTO song = new SongDTO();
if(song.getTrack() == track) {
return song;
}
return null;
}
}
Main
package com.techm.react.Wasteland;
import com.techm.react.Wasteland.controller.AlbumController;
import com.techm.react.Wasteland.controller.SongController;
import com.techm.react.Wasteland.service.SongService;
import org.modelmapper.ModelMapper;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#SpringBootApplication
#ComponentScan({"com.server", "com.server.config"})
#EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class WastelandApplication {
#Bean
public ModelMapper modelMapper() {
ModelMapper modelMapper = new ModelMapper();
return modelMapper;
}
public static void main(String[] args) {
SpringApplication.run(WastelandApplication.class, args);
SongService songService = new SongService();
System.out.println(songService.findAllSongs());
}
}
When you use new to create an object, it's outside of Spring's context. It won't have the autowired dependencies. Also, you won't be able to use autowired beans in your main (nor should you) as it's a static method. If you want to do this in your app startup, autowire the bean and put the logic in a PostConstruct method.
Here is an example:
public class WastelandApplication {
#Autowired
private SongService songService;
#Bean
public ModelMapper modelMapper() {
ModelMapper modelMapper = new ModelMapper();
return modelMapper;
}
public static void main(String[] args) {
SpringApplication.run(WastelandApplication.class, args);
}
#PostConstruct
public void doSomethingIProbablyShouldNotBeDoing() {
System.out.println(songService.findAllSongs());
}
}
I am new to Boot-Spring apparently, I mostly copy some code from youtube on this case. However, after modification, in the end, I got a message like this;
APPLICATION FAILED TO START
Description:
Field postService in com.example.demo.BlogController required a bean of type 'Server.PostService' that could not be found.
Action:
Consider defining a bean of type 'Server.PostService' in your configuration.
.....Any idea how to deal with this situation. Thank you for the support.
1stclass-BlogApplciation-----com.example.demo(package)
2nd-Blog Controller--------same package as BlogApplication
3rdclass-Post---entities
4rthclass-PostRepositories---Repositories
**package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class BlogApplication {
public static void main(String[] args) {
SpringApplication.run(BlogApplication.class, args);
}
}**
**package com.example.demo;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import Server.PostService;
import entities.Post;
import java.util.Date;
#RestController
public class BlogController {
#Autowired
private PostService postService;
#GetMapping(value="/")
public String index() {
return "index";
}
#GetMapping(value="/posts")
public List<Post>posts(){
return postService.getAllPosts();
}
#PostMapping(value="/post")
public void publishPost(#RequestBody Post post) {
if(post.getDatecreation() == null)
post.setDatecreation(new Date());
postService.insert(post);
}
}**
**package entities;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
#Entity
public class Post {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String title;
private String body;
private Date Datecreation;
public Post() {
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String gettitle() {
return title;
}
public void settitle(String title) {
this.title= title;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public Date getDatecreation() {
return Datecreation;
}
public void setDatecreation(Date datecreation) {
this.Datecreation = datecreation;
}
}**
**package Repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import entities.Post;
#Repository
public interface PostRepository extends JpaRepository<Post,Long>{
}**
Your BlogApplication Class, which is the class annotated with #SpringBootApplication is in the package com.example.demo. That means that, by default, Spring is going to launch a Component Scan starting from that package.
The problem is that your class PostService and your interface PostRepository are not in the same package as (or in a sub-package of) com.example.demo, so Spring can't find them and won't automatically create these beans for you.
To correct this issue, move the packages you created inside your root package (com.example.demo).
You can find more information about the use of #SpringBootApplication here.
EDIT:
You are missing PostService class or you have imported incorrect class as Server.PostService.
try to create a service like this one:
#Component
public class PostService {
public List<Post> getAllPosts(){
//your code
}
}
I'm trying to configure mongodb auditing in my spring boot app, and I having this error when trying to persist my domain class:
java.lang.IllegalArgumentException: Couldn't find PersistentEntity for type class com.example.hateoasapi.domain.Post!
Docs from here https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#auditing says that all this configs enough, but I don't know why it doesn't work in my project. Could someone help me?
My mongodb config class:
package com.example.hateoasapi.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
import org.springframework.data.mongodb.config.EnableMongoAuditing;
import org.springframework.data.mongodb.core.MongoTemplate;
import com.mongodb.MongoClient;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import java.util.Collection;
import java.util.Collections;
#Configuration
#EnableMongoAuditing
#EnableMongoRepositories(value = "com.example.hateoasapi.repository")
public class MongoConfig extends AbstractMongoConfiguration {
#Value("${spring.data.mongodb.database}")
private String databaseName;
#Value("${spring.data.mongodb.host}")
private String databaseHost;
#Value("${spring.data.mongodb.port}")
private Integer databasePort;
#Override
protected String getDatabaseName() {
return this.databaseName;
}
#Bean
#Override
public MongoClient mongoClient() {
return new MongoClient(databaseHost, databasePort);
}
#Bean
public MongoTemplate mongoTemplate() {
return new MongoTemplate(mongoClient(), databaseName);
}
#Override
protected Collection<String> getMappingBasePackages() {
return Collections.singleton("com.example.hateoasapi.domain");
}
}
AuditorAware implementation:
package com.example.hateoasapi.config;
import com.example.hateoasapi.domain.User;
import org.springframework.data.domain.AuditorAware;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import java.util.Optional;
#Component
public class SecurityAuditor implements AuditorAware<User> {
#Override
public Optional<User> getCurrentAuditor() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || !authentication.isAuthenticated()) {
return null;
}
return Optional.of((User) authentication.getPrincipal());
}
}
And my domain class:
package com.example.hateoasapi.domain;
import javax.persistence.Id;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import org.joda.time.DateTime;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.hateoas.ResourceSupport;
import com.fasterxml.jackson.annotation.JsonCreator;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import static org.springframework.hateoas.mvc.ControllerLinkBuilder.*;
import java.io.Serializable;
import java.util.List;
import com.example.hateoasapi.controller.*;
#Getter
#Setter
#ToString
#Document
public class Post extends ResourceSupport implements Serializable {
#Id
#Field(value = "_id")
private String objectId;
#DBRef
private List<Comment> comments;
#DBRef
private User author;
#NotBlank
private String body;
#NotBlank
private String title;
private String categoryId;
#NotEmpty(message = "Tags cannot be empty")
private List<PostTag> tags;
#CreatedDate
private DateTime createdDate;
#LastModifiedDate
private DateTime lastModifiedDate;
#CreatedBy
private User createdBy;
private Long views;
private List<PostRating> likes;
private List<PostRating> dislikes;
#JsonCreator
public Post() {}
public Post(String title, String body) {
this.body = body;
this.title = title;
}
public Post(User author, String body, String title, String categoryId, List<PostTag> tags) {
this.author = author;
this.body = body;
this.title = title;
this.categoryId = categoryId;
this.tags = tags;
}
public void addLinks() {
this.add(linkTo(methodOn(PostController.class).getAllPosts(null)).withSelfRel());
}
}
I solved this issue with the next configuration:
#Configuration
#EnableMongoRepositories(basePackages = "YOUR.PACKAGE")
#EnableMongoAuditing
public class MongoConfig extends AbstractMongoConfiguration {
#Value("${spring.data.mongodb.host}")
private String host;
#Value("${spring.data.mongodb.port}")
private Integer port;
#Value("${spring.data.mongodb.database}")
private String database;
#Override
public MongoClient mongoClient() {
return new MongoClient(host, port);
}
#Override
protected String getDatabaseName() {
return database;
}
#Bean
public MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongoDbFactory(), mappingMongoConverter());
}
#Bean
public MongoDbFactory mongoDbFactory() {
return new SimpleMongoDbFactory(mongoClient(), database);
}
}
just add the bean for MongoTemplate with the constructor of MongoTemplate(MongoDbFactory mongoDbFactory, #Nullable MongoConverter mongoConverter)
Quoting from JIRA ticket
You need to pipe the MappingMongoConverter that's available in the environment into MongoTemplate as well, i.e. use new MongoTemplate(dbFactory, converter). The constructor you use is for convenience, one-off usages. We usually recommend to use AbstractMongoConfiguration in case you'd like to customize anything MongoDB specific as this makes sure the components are wired together correctly.
More specifically, you need to inject pre-configured MappingMongoConverter or if you need to use your own converter, at least use pre-configured MongoMappingContext.
I had this problem also with spring boot 2.2
I had both #EnableMongoRepositories and #EnableMongoAuditing as configuration and i got the error Couldn't find PersistentEntity for type class
the problem in my case was the structure of the packages: Application class was a level lower than part of my model that used auditing.
I found on many forum posts that the 2 annotations are not compatible together in spring 2.2, but after restructuring the packages I was able to use both with success in spring boot 2.2
If you use the last version of Spring boot (2.0) and Spring Data, #EnableMongoAuditing
#EnableMongoRepositories are not compatible. It's the same with EnableReactiveMongoRepositories annotation.
If you want to enable mongo auditing, you need to remove your MongoConfig class, use config file to define your mongodb connection and everything will work.
If you use the last version of Spring boot (2.0) and Spring Data, #EnableMongoAuditing and #EnableMongoRepositories, try remove #EnableMongoRepositories. It should be working just this sample project - https://github.com/hantsy/spring-reactive-sample/tree/master/boot-data-mongo
I'm trying to autowire a CrudRepository in a DTO class but Spring always injects null instead of bean .
My code looks like :
package com.exampleRestApp.task;
import com.exampleRestApp.workers.WorkerRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
public class TaskDTO {
private int workerID;
private String name;
boolean finished;
private int taskID;
#Autowired
WorkerRepository w; //w==null in this moment
public Task MapToEntity() {
Task task = new Task();
task.setName(name);
task.setFinished(finished);
task.setTaskID(taskID);
task.setWorker(w.findOne(task.getTaskID()));
return task;
}
And my WorkerRepo :
package com.exampleRestApp.workers;
import java.util.List;
public interface WorkerRepository extends CrudRepository<Worker,Integer> {
List<Worker> findBySurname(String surname);
List<Worker>findAllByOrderByNameAsc();
}
You have to annotate your WorkerRepository with #Repository or #Service spring annotations
#Repository
public interface WorkerRepository extends CrudRepository<Worker,Integer>