Sprint error querying embedded documents in mongoDB - spring

I have a
#Data
#Document(collection = "req_language")
public class Language implements ChangeDto {
#Id
private String id = UUID.randomUUID().toString();
private String name;
private String code;
private Boolean active = Boolean.TRUE;
private Boolean deleted = Boolean.FALSE;
private Date changeAt = Date.from(Instant.now());
private String changedBy;
private String correlationId = UUID.randomUUID().toString();
}
And
#Data
#Document(collection = "req_locale")
public class Locale implements ChangeDto {
#Id
private String id = UUID.randomUUID().toString();
private String description;
private Language language;
private String code;
private String fatherCode;
private Boolean active = Boolean.TRUE;
private Boolean deleted = Boolean.FALSE;
private Date changedAt = Date.from(Instant.now());
private String changedBy;
private String correlationId = UUID.randomUUID().toString();
}
With a simple repository
#Repository
#JaversSpringDataAuditable
public interface LocalesRepository extends MongoRepository<Locale, String>, LocalesCustom {
List<Locale> findByCode(String code);
}
If a try to use the findByCode, I receive this error:
No converter found capable of converting from type [java.lang.String] to type [XXX.Language]
When I try to use query in the LocalesCustom, for example (empty)
Query query = new Query();
List<Locale> localeList = mongoTemplate.find(query, Locale.class);
Same error
I have tried #DBRef in Language, and popped others errors (I couldn't query by the language code, query.addCriteria(Criteria.where("language.code")) in LocalesRepository.
There's a right way to do it?

Related

MapStruct - mapping method from iterable to non-iterable

I have been working with MapStruct some days now and haven't yet achieved what i need.
As part of the exercises with Spring, I am writing a small app that will display information about the movies (title, description, director, etc.) and additionally the movie category.
Therefore, I created an additional Entity called Category, so that (e.g. an admin) could add or remove individual category names.
Movie Entity:
public class Movie {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String content;
private String director;
private int year;
#ManyToMany
#Column(nullable = false)
private List<Category> category;
private LocalDate createdAt;
}
Category Entity
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String categoryName;
private LocalDate createdAt;
}
I packed it all into MapStruct and DTOs.
MovieDTORequest.java
public class MovieDTORequest {
private String title;
private String content;
private String director;
private List<Category> category;
private int year;
}
MovieDTOResponse.java
public class MovieDTOResponse {
private String title;
private String content;
private String director;
private String categoryName;
private int year;
private LocalDate createdAt;
}
And MovieMapper.java
#Mapper(componentModel = "spring")
public interface MovieMapper {
#Mapping(target = "categoryName", source = "category")
MovieDTOResponse movieToMovieDTO(Movie movie);
#Mapping(target = "id", source = "title")
#Mapping(target = "createdAt", constant = "")
Movie movieRequestToMovie(MovieDTORequest request);
#Mapping(target = "id", source = "title")
#Mapping(target = "createdAt", constant = "")
void updateMovie(MovieDTORequest request, #MappingTarget Movie target);
String map(List<Category> value);
}
However, I have a problem with Mapper. First, I got the error:
"Can't map property "List<Category> category" to "String categoryName". Consider to declare/implement a mapping method: "String map(List<Category> value)"
and when I wrote it in Mapper, I have one more error:
Can't generate mapping method from iterable type from java stdlib to non-iterable type.
I am asking for help, because I am already lost.
You should define default implementation for String map(List<Category> value) inside MovieMapper interface, what would Mapstruct use to map property List<Category> category to String categoryName. For example:
#Mapper(componentModel = "spring")
public interface MovieMapper {
#Mapping(target = "categoryName", source = "category")
MovieDTOResponse movieToMovieDTO(Movie movie);
default String map(List<Category> value){
//TODO: Implement your own logic that determines categoryName
return "Movie Categories";
}
}

Infinite recursion with #JsonManagedReference and #JsonBackReference

I have an entity class that is self referencing itself. For example, a document can be linked to a parent document.
#Entity
#Table(name = "documents")
public class DocumentEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#JsonIgnore
#JsonManagedReference
#ManyToOne(fetch = FetchType.LAZY)
private DocumentEntity parentDocument;
#JsonBackReference
#OneToMany(mappedBy = "parentDocument", fetch = FetchType.LAZY)
private Set<DocumentEntity> documents;
#Column(nullable = false, unique = true)
private String documentId;
#Column(nullable = false)
private String fileName;
}
In my entry point / controller layer :
#GetMapping(
path = "/{fileId}",
produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE }
)
public DocumentResponse getParentDocument(#PathVariable("fileId") String fileId) {
modelMapper = createModelMapper();
DocumentDto documentDto = documentService.getParentDocument(fileId);
DocumentResponse documentResponse = modelMapper.map(documentDto, DocumentResponse.class);
documentResponse.getDocuments().forEach(document -> System.out.println(document.getDocumentId()));
return documentResponse;
}
In my Service layer :
#Override
public DocumentDto getParentDocument(String documentId) {
DocumentDto documentDtoResponse = new DocumentDto();
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
DocumentEntity storedDocumentEntity =
documentRepository.findByDocumentIdAndParentDocumentNull(documentId);
if(storedDocumentEntity.getDocumentId().isEmpty() || storedDocumentEntity.getDocumentId().isBlank()) {
throw new AppFileNotFoundException("Oops file not found");
}
documentDtoResponse = modelMapper.map(storedDocumentEntity, DocumentDto.class);
return documentDtoResponse;
}
In the repository:
Now I'm making a sql request in a repository interface that extends JpaRepository.
The application allow to have a parent document with child documents and child documents cannot have child documents.
#Repository
public interface DocumentRepository extends JpaRepository<DocumentEntity, Long> {
DocumentEntity findByDocumentIdAndParentDocumentNull(String documentId);
}
I also tried to implement the method using JPQL :
#Query("SELECT d FROM DocumentEntity d WHERE d.documentId = :documentId AND d.parentDocument IS NULL")
DocumentEntity findByDocumentIdAndParentDocumentNull(String documentId);
This query allow to get parent documents and child documents.
My code implementation separates response and database by using a DTO layer.
Issue:
My issue is that I obtain an infinite recursion. I think i'm using #JsonManagedReference and #JsonBackReference correctly. Even adding the same annotations to DTO pojo do not solve issue. If i add those annotation to response POJO, then I do not obtain child documents.
Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException
Inially I have a DTO class that also self refers to itself.
public class DocumentDto implements Serializable {
private String filePath;
private String mimeType;
private String documentType;
private DocumentDto parentDocument;
Set<DocumentDto> documents;
}
I created a second class without properties that are causing problems;
public class DocumentChildDto implements Serializable {
private String filePath;
private String mimeType;
private String documentType;
}
In the DocumentDto I simply replaced the DocumentDto with DocumentChildDto.
public class DocumentDto implements Serializable {
private String filePath;
private String mimeType;
private String documentType;
private DocumentChildDto parentDocument;
Set<DocumentChildDto> documents;
}
It's more a hack than a technical solution but it works fine. Here childDocumentDto object won't load the parentDocument.

CQEngine Query nested object using parser.retrieve

I have a nested object like
public class SQSMessage implements Serializable {
private String type;
private boolean isEntity;
private String eventType;
private SystemInfo systemInfo;
private DomainAttributes domainAttributes;
#Data
public static class SystemInfo implements Serializable {
private String identifier;
private String ownedBy;
private Payload payload;
private EntityTags entityTags;
private long createdOn;
private String createdBy;
private long version;
private long lastUpdatedOn;
private String lastUpdatedBy;
private String attrEncKeyName;
#Data
public static class Payload implements Serializable {
private String bucketName;
private String objName;
private String encKeyName;
private byte[] payloadBytes;
private byte[] decryptedBytes;
private byte[] sanitizedBytes;
}
#Data
public static class EntityTags implements Serializable {
private List<Tag> tags;
#Data
public static class Tag implements Serializable {
private String tagName;
private String tagValue;
}
}
}
#Data
public static class DomainAttributes implements Serializable {
private String updatedByAuthId;
private String saveType;
private String docName;
private String ceDataType;
private String year;
private String appId;
private String formSetId;
private String appSku;
private String deviceId;
private String deviceName;
}
}
I would like to query the collection of SQSObjects by applying a filter like
ResultSet<SQSMessage> results = parser.retrieve(indexedSQSMessage, "SELECT * FROM indexedSQSMessage WHERE type='income' and DomainAttributes.saveType in ('endSession', 'cancelled')or (DomainAttributes.countryCode is null or DomainAttributes.countryCode='US'");
Is that possible using CQEngine? if yes.. please send me the examples.
The reason why I want o make that as sql... where clause is dynamic for various use cases.
Your example is more complicated than it needs to be for the question, so I am just skimming it. (Read about SSCCE)
However generally this kind of thing should be possible. See this related question/answer for how to construct nested queries: Can CQEngine query an object inside another object
If you set up attributes like that, you should be able to use them in SQL queries as well as programmatically.

Return type of JPA Repository 'getOne(id)' Method

I have the following Spring boot service for an object of type Report -
#Service
public class ReportService {
#Autowired
private ReportRepository reportRepository;
#Autowired
private UserRepository userRepository;
/*get all reports */
public List<Report> getAllReports(){
return reportRepository.findAll();
}
/*get a single report */
public Report getReport(Long id){
return reportRepository.getOne(id);
}
//other similar methods....
}
The problem arises while retrieving a single Report. If a report ID is send which doesn't exist, the following error is generated...
DefaultHandlerExceptionResolver : Failed to write HTTP message:
org.springframework.http.converter.HttpMessageNotWritableException: Could not
write JSON: Unable to find com.interact.restapis.model.Report with id 16;
nested exception is com.fasterxml.jackson.databind.JsonMappingException:
Unable to find com.interact.restapis.model.Report with id 16 (through
reference chain:
com.interact.restapis.model.Report_$$_jvst83c_1["fromUserId"])
Below is the code for my Report Controller
#RestController
public class ReportController {
#Autowired
private ReportService reportService;
//Get all reports
#GetMapping("/interactions")
public List<Report> getAllReports() {
return reportService.getAllReports();
}
//Get single report
#GetMapping("/interactions/{id}")
public ResponseEntity<Report> getReport(#PathVariable Long id) {
if(reportService.getReport(id) == null)
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
return new ResponseEntity<>(reportService.getReport(id), HttpStatus.OK);
}
#PostMapping("/interactions")
public ResponseEntity<Report> addReport(#RequestBody Report report) {
Report report1 = reportService.addReport(report);
if(report1 == null)
return new ResponseEntity<>(report, HttpStatus.NOT_FOUND);
return new ResponseEntity<>(report1, HttpStatus.OK);
}
//Other request methods...
}
Below is the code for my Report Model class -
#Entity
#Table (name = "report")
#EntityListeners(AuditingEntityListener.class)
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Report {
#Id
#Column (name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "from_user_id")
private Long fromUserId;
#Column(name = "to_user_id")
private Long toUserId;
#Column(name = "to_user_email")
private String toUserEmail;
#Column(name = "from_user_email")
private String fromUserEmail;
#Temporal(TemporalType.DATE)
#JsonFormat(pattern = "dd-MM-yyyy hh:mm:ss")
#CreatedDate
private Date createdAt;
#Column(nullable = false)
private String observation;
#Column(nullable = false)
private String context;
private String recommendation;
#Column(nullable = false)
private String eventName;
#Temporal(TemporalType.DATE)
#JsonFormat(pattern = "dd-MM-yyyy hh:mm:ss")
#Column(nullable = false)
private Date eventDate;
private boolean isAnonymous;
#Temporal(TemporalType.DATE)
#JsonFormat(pattern = "dd-MM-yyyy hh:mm:ss")
private Date acknowledgementDate;
#OneToMany(cascade = CascadeType.ALL, targetEntity = Action.class)
#JoinColumn(name = "report_id")
private List<Action> actionList;
#Value("${some.key:0}")
private int rating; //Range 0 to 4
private int type;
/*
Getter and setter methods...
*/
}
I want to know if reportRepository.getOne(Long id) returns null so that I can actually check if a particular report doesn't exist in the database. If not, how else can I implement the above?
The JpaRepository.getOne with throw EntityNotFoundException if it couldn't find a record with the given id.
You can use CrudRepository.findById (JpaRepository is a subclass of CrudRepository) which will return an Optional<Report> which can be empty if there are no record for the given id. You can use Optional.isPresent() to check whether it a Report is available or not and take actions accordingly.
Create a method in your ReportRepository.
It will return Report by matched id else return null.
public Optional<Report> findById(Long id);
Note: findById(Long id); should match with the property name in your Report entity.
I am assuming your Report entity is as follows:
public class Entity{
private Long id;
...
}

how to use spring data neo4j search for fulltext

I am learning spring data neo4j and spring .I want to search fulltext,for example I have three Movies (sky,sky1,sky2),when i search "sky",it return sky,sky1,sky2.firt i use repository below
package com.oberon.fm.repository;
#Repository
public interface MovieRepository extends GraphRepository<Movie> {
Movie findById(String id);
Page<Movie> findByTitleLike(String title, Pageable page);
}
My controller below
#RequestMapping(value = "/movies", method = RequestMethod.GET, headers = "Accept=text/html")
public String findMovies(Model model, #RequestParam("q") String query) {
log.debug("1");
if (query != null && !query.isEmpty()) {
Page<Movie> movies =movieRepository.findByTitleLike(query, new PageRequest(0, 20));
model.addAttribute("movies", movies.getContent());
} else {
model.addAttribute("movies", Collections.emptyList());
}
model.addAttribute("query", query);
addUser(model);
return "/movies/list";
}
these does not work well,i think somewhere might be wrong,but i dont know,if you have any idea,tell me thanks! by the way,it throw exception java.lang.NullPointerException.
My Movie entity
#NodeEntity
public class Movie {
#GraphId
Long nodeId;
#Indexed(indexType = IndexType.FULLTEXT, indexName = "id")
String id;
#Indexed(indexType = IndexType.FULLTEXT, indexName = "search")
String title;
String description;
#RelatedTo(type = "DIRECTED", direction = INCOMING)
Set<Director> directors;
#RelatedTo(type = "ACTS_IN", direction = INCOMING)
Set<Actor> actors;
#RelatedToVia(type = "ACTS_IN", direction = INCOMING)
Iterable<Role> roles;
#RelatedToVia(type = "RATED", direction = INCOMING)
#Fetch
Iterable<Rating> ratings;
private String language;
private String imdbId;
private String tagline;
private Date releaseDate;
private Integer runtime;
private String homepage;
private String trailer;
private String genre;
private String studio;
private Integer version;
private Date lastModified;
private String imageUrl;

Resources