JaversException PROPERTY_NOT_FOUND: Property in derived class not found in abstract class - javers

I have a model looking something like this:
#Data
public abstract class InputFormGroup
{
String id;
String name;
String text;
String type;
}
#Data
public class SimpleInputFormGroup extends InputFormGroup
{
InputControl inputControl;
InputFormAnswerRow answerRow;
}
#Data
public class InputFormPage
{
String id;
String name;
String title;
List<InputFormGroup> inputFormGroups = new LinkedList<>();
}
In effect I have a larger structure that in it has InputFormPages that has one or more InputFormGroups that can be of type SimpleInputFormGroup (and also other types that I have not included in this example).
Im using MongoRepository to persist them and everything looks very nice and I can query the changes on the Entity object and it all looks good.
The only time I have an issue is when I try to query with a path. In this example "..../inputFormPages/0/inputFormGroups/0/answerRow/answers/0".
Then I get the exception because the framework finds a list of InputFormGroup but then when it looks for answerRow in the abstract InputFormGroup base class it does naturally not find it. Is there some way to configure the model so the framework also looks in the derived classes for, in this case, the answerRow parameter? Of is it as simple as the framework doesn't support polymorphism in this way?
The error I got:
"JaversException PROPERTY_NOT_FOUND: Property 'answerRow' not found in class 'com.replior.ebrmockupbackend.model.InputFormGroup'. If the name is correct - check annotations. Properties with #DiffIgnore or #Transient are not visible for JaVers."
And the Query:
JqlQuery query = QueryBuilder.byValueObjectId(batch1.getId(),Batch.class,"inputForm/inputFormSteps/2/inputFormPages/0/inputFormGroups/0/answerRow/answers/0").withChangedProperty("value").build();
List<Change> changes = javers.findChanges(query);
And the version:
<dependency>
<groupId>org.javers</groupId>
<artifactId>javers-spring-boot-starter-mongo</artifactId>
<version>3.10.2</version>
</dependency>
Appreciate any help I can get.
Link to project that exemplifies the issue:
Github project

This issue is fixed in JaVers 3.11.3

Related

Class based projections using a DTO in Spring Data Jpa is not working

In my Spring Boot application, I am trying to implement a class based projection using DTOs as described at:
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#projections.dtos
I have a domain class that looks like:
#Entity
#Table(name="metadatavalue")
public class MetadataValue {
#Id
#Column(name="metadata_value_id")
private Integer metadataValueId;
#Column(name="resource_id", insertable=false, updatable=false)
private Integer resourceId;
#Column(name="metadata_field_id", insertable=false, updatable=false)
private Integer metadataFieldId;
#Column(name="text_value")
private String textValue;
more class members, getters and setters, etc follow.
I also have a simple DTO class with one member:
public class MetadataDTO {
private String textValue;
public MetadataDTO(String textValue) {
this.textValue = textValue;
}
public String getTextValue() {
return textValue;
}
}
My repository class is:
public interface MetadataValueRepository extends CrudRepository<MetadataValue, Integer> {
#Query("SELECT m from MetadataValue m WHERE m.handle.handle = :handle AND m.resourceTypeId=m.handle.resourceTypeId")
List<MetadataValue> findAllByHandle(#Param("handle") String handle);
#Query("SELECT new path.to.my.package.domain.MetadataDTO(m.textValue AS textValue) FROM MetadataValue m "
+ "WHERE m.handle.handle = :handle AND m.resourceTypeId=m.handle.resourceTypeId")
List<MetadataDTO> findAllByHandleDTO(#Param("handle") String handle);
}
The first method, findAllByHandle works as expected, but when running the second method, findAllByHandleDTO, which I had hoped to return the projection, my application throws the error:
java.lang.IllegalArgumentException: Couldn't find PersistentEntity for type class path.to.my.package.domain.MetadataDTO!
I have also tried extending from JpaRepository with the same result. In another attempt, I tried using an Interface based projection which resulted in an almost identical stacktrace, with an internal class substituted for my class.
My project is spring-boot 2.3.0 with Spring Web, Spring Data JPA, Rest Repositories, and PostgreSQL Driver.
Can anybody help me understand what I am doing wrong and set me in the right direction?
Thanks so much!
Update on this question: (I have added the tag spring-data-rest). Experimenting, I have learned that I can successfully call my method, for instance, in the run() method of my application class. It's only when I call the method as a rest endpoint that I see the error. Is this simply an issue of incompatibility with Spring Data Rest?

Elasticsearch returns empty json-objects

I'm just getting started with elasticsearch with spring which is both technologies which are completely new to me. I have uploaded data to an elasticseach index with logstash and I can search it successfully using kebana. However when I try to return from an index to a webpage using spring it only returns empty json-objects, but the right amount of empty objects. Did I upload the data incorrectly or is something wrong with my code? I don't understand why this is happening and would appreciate any help I can get. You can find some code below.
Code for type:
#Document(indexName="usmgbg_index", type="usmgbg_type")
public class Usmgbg {
#Id
private String ID;
private String Source, Name, Profession, Country, FileName, LastModified, OwnerID;
}
Repository:
#Repository
public interface UsmgbgRepository extends ElasticsearchRepository<Usmgbg, String>{}
Controller:
#RestController
public class UsmgbgController {
#Autowired
private UsmgbgRepository repository;
#GetMapping("usmgbg/findall")
public List<Usmgbg> findAllCustomers() {
List<Usmgbg> items = new ArrayList<>();
repository.findAll().forEach(items::add);
return items;
}
}
The output I'm getting from findAllCustomers looks like:
[{},{},{},{},....]
I realize this is an old question but I had the same issue (maybe for a different reason) and I solved it by adding getters and setters in the model.
Iterable is returned from findAll().
If you want to get list you should get content first.
Change
#Repository
public interface UsmgbgRepository extends
ElasticsearchRepository<Usmgbg, String>{
Page<Usmgbg> findAll();
}
And then
repository.findAll().getContent().forEach(items::add);
Or fix your code to iterate over the results.
Another solution is to use search method in ElasticsearchRepository using QueryBuilders API.
Iterable<Usmgbg>=
repository.search(QueryBuilders.matchAllQuery);
Adding my experience
spring-data requires getters to follow the POJO naming, i.e: getSomething()
so it did not work (spring-data did not send any fields to ElasticSearch when saving the #Document, resulting in an empty _source in ES) when having Lombok #Accessors(fluent = true), as it removes the get prefix on getters ...

Spring Data JPA Repository Method Query Cannot Parse Property Name Following OrderBy

My Repository Method Query cannot parse a property name that comes after the OrderBy, but it can if it follows the findBy or findAllBy. The attribute in my entity that is giving me issues is zIndex
Entity Class
#Entity
public class DisplayLayer
{
#Id
#Column(name="DISPLAY_LAYER_ID")
private Long id;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name="DISPLAY_CONTAINER_ID")
private DisplayContainer displayContainer;
#Column(name="NAME")
private String name;
#Column(name="Z_INDEX")
private Long zIndex;
#Column(name="DESCRIPTION")
private String description;
// Getters & Setters
}
Repository Class
public interface DisplayLayerRepository extends BaseRepository<DisplayLayer, Long>
{
// This one method query works just fine
public List<DisplayLayer> findByZIndex(Long pZIndex);
// These two throw the same error:
// Unable to locate Attribute with the the given name [ZIndex]
//
// public List<DisplayLayer> findAllByOrderByZIndexAsc();
// public List<DisplayLayer> findByDisplayContainerIdOrderByZIndexAsc(Long pDisplayLayerId);
}
So in my first method query, when OrderBy is not used, it correctly parses it as [zIndex], but when it follows the OrderBy for some reason it capitalizes the z: [ZIndex].
Is this a known issue, or am I doing something wrong?
EDIT
What makes me think there might be a bug with the parser is that if I update zIndex to IndexZ in my entity and then change my query methods from OrderByZIndex to OrderByIndexZ everything works.
This solution is not ideal though as the database table is Z_INDEX and that has a specific meaning when talking about layering of graphics.
Yes there is a bug but there is a simple workaround, please try :
displayLayerRepository.findAll(Sort.by(Sort.Order.desc("zIndex").ignoreCase()));
I suppose DisplayLayerRepository extends JpaRepository.
It's similar when you use parameters in your findBy method. Define in your repository empty method :
public List<DisplayLayer> findByDisplayContainerId(Long pDisplayLayerId, Sort sort);
Then you can call it by :
displayLayerRepository.findByDisplayContainerId(1L, Sort.by(Sort.Order.desc("zIndex").ignoreCase()));
You can use JpaSort in query. As in your case, it looks something like this:
Sort sort = JpaSort.unsafe(Sort.Direction.ASC, "zIndex");
List<DisplayLayer> zIndexes = displayLayerRepository.findByZIndex(pZIndex, sort);
and your query in Repository will look like this:
public List<DisplayLayer> findByZIndex(Long pZIndex, Sort sort);

Why spring create tow identical links for self and rel?

I cannot get why spring create the same links for self and rel? Is there a way how to disable it? I think that this only my issue because I didn't meet such problem in docs I read.
Here is my entity mapping:
#Getter
#Setter
#Document
public class Ad {
#Id
private String id;
private String description;
private Banner banner;
}
#Getter
#Setter
public class Banner {
private String id;
private String filename;
}
Here is my repository:
#RepositoryRestResource
public interface AdRepository extends CrudRepository<Ad, String> {
}
I touch the following url: http://localhost:8558/ads
I don't use any projections. My app is quite primitive now. There is nothing specific.
Thanks in advance!
My only guess is that maybe you're missing hashCode/equals and that's causing a problem
This is by design. The rel-based link allows you to see all contexts, while self link serves as the canonical link.
To further clarify, adjust your repository definition to extend not CrudRepository, but instead PagingAndSortingRepository. The two links rendered for each aggregate root will immediately look slightly different due to extended templating options.

Spring Data Redis Repository support does not read back embedded complex objects

I have a spring-boot application (1.4RC1, I know it's RC, but Spring Data Redis 1.7.2 is not) where I'm using spring-boot-starter-redis.
The application uses a Spring Data Repository (CrudRepository) which should save an object (using #RedisHash annotation) with String and Boolean properties and one custom class property, which also has only Strings and Longs as properties.
When I save an object (via the repository), everything went fine and I can see all the properties in the database as I would expect.
When I want to read the data from the database (via the repository) I only get the properties from the parent object. The custom class property is null.
I would expect to get the property loaded from the database as well. As the documentation states you can write a custom converter, but since I don't need to do that, when I want to write the data, I shouldn't need to write a reading converter as well.
I wonder if I need to annotate the custom class property, but I couldn't find anything in the documentation. Can you point me in the right direction?
The classes are as follows:
Class sample:
#Data
#EqualsAndHashCode(exclude = {"isActive", "sampleCreated", "sampleConfiguration"})
#RedisHash
public class Sample {
#Id
private String sampleIdentifier;
private Boolean isActive;
private Date sampleCreated;
private SampleConfiguration sampleConfiguration;
public Sample(String sampleIdentifier, SampleConfiguration sampleConfiguration){
this.sampleIdentifier = sampleIdentifier;
this.sampleConfiguration = sampleConfiguration;
}
}
Class SampleConfiguration:
#Data
public class SampleConfiguration {
private String surveyURL;
private Long blockingTime;
private String invitationTitle;
private String invitationText;
private String participateButtonText;
private String doNotParticipateButtonText;
private String optOutButtonText;
private Long frequencyCappingThreshold;
private Long optOutBlockingTime;
}
I added #NoArgsConstructor to my Sample class as Christoph Strobl suggested. Then the repository reads the SampleConfiguration correctly. Thanks, Christoph!

Resources