I have a SpringBoot 2 app that uses using Couchbase as a database, Spring-Boot and Spring-Data and Lombok fot the getters and equals method
I have created this Repository
#ViewIndexed(designDoc = "bendicionesDoc")
public interface BenRepository extends CouchbaseRepository<BendicionesDoc, String> {
#Query("#{#n1ql.selectEntity} where #{#n1ql.filter} AND ANY uuid IN data.identifier.id SATISFIES uuid = $1 END")
List<BendicionesDoc<Item>> findById(String id);
}
and here all the objects created with Lombok library
public class BendicionesDoc<T>implements Serializable {
#Field
private T data;
}
and
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#JsonInclude(NON_NULL)
public class Item {
private List<Identifier> identifier;
}
and
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#JsonInclude(NON_NULL)
#EqualsAndHashCode
public class Identifier {
private String id;
private MasterServant idContext;
private MasterServant idScope;
}
and
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#JsonInclude(NON_NULL)
#EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class MasterServant {
private String context;
#JsonValue
#EqualsAndHashCode.Include
private String value;
private Name valueDescription;
#JsonCreator
public MasterServant(String value) {
this.value = value;
}
}
But when I run the repository query I got always 0 results, even there are docs. in the DB:
You need to define your reference type in CouchbaseRepository<T, K> then simply add the reference type Item as CouchbaseRepository<BendicionesDoc<Item>, String> and just use Repository query keywords for findById(String id).
public interface BenRepository extends CouchbaseRepository<BendicionesDoc<Item>, String> {
List<BendicionesDoc<Item>> findById(String id);
}
Related
I'm trying to create a mapper using lombok #Mapper and I get the following error:
Property "delivery" has no write accessor in ClassA for target name "classBB_variable.delivery"
The code:
#Mapper
#Mapping(target = "classBB_variable.customerId", source = "classA_variable.customerId")
#Mapping(target = "classBB_variable.delivery", source = "classA_variable.classAA_variable.delivery")
ClassB toCreateRequest(ClassA classA_variable);
#Value
#Builder(toBuilder = true)
public class ClassA {
private UUID customerId;
private ClassAA classAA_variable;
}
#Data
#Builder
public class ClassAA {
private String delivery;
}
#Data
#Builder
public class ClassB {
private ClassBB classBB_variable;
}
#Data
#Builder
public class ClassBB {
private UUID customerId;
private String delivery;
}
As the map for customerId works fine, I'm assuming the issue is the additional level introduced with classA_variable.classAA_variable.delivery.
Has anyone already dealt with this situation? How can I solve it?
I'm playing around with generics and Spring Data repository. I created a simple project with almost zero configuration, entities are in subpackage of main class.
Entity
#Data
#ToString(callSuper = true)
#Entity
public class Person extends GenericEntity {
private String name;
}
#Data
#MappedSuperclass
public class GenericEntity {
#Id
#GeneratedValue
private Integer id;
#CreationTimestamp
#Column(name = "TMS_INSERIMENTO")
private LocalDateTime tmsInserimento;
#UpdateTimestamp
#Column(name = "TMS_AGGIORNAMENTO")
private LocalDateTime tmsAggiornamento;
}
Repository
public interface GenericRepository<T extends GenericEntity> extends JpaRepository<T, Integer> {
}
Service
public List<Person> findAllPeople() {
return genericRepository.findAll();
}
Call to findAll() throws the following exception:
org.springframework.dao.InvalidDataAccessApiUsageException: Not an entity: class com.example.demot.entity.GenericEntity; nested exception is java.lang.IllegalArgumentException: Not an entity: class com.example.demot.entity.GenericEntity
Try with the following
#Data
#MappedSuperclass
public class GenericEntity <T extends GenericEntity> {
...
}
And then
#Data
#ToString(callSuper = true)
#Entity
public class Person extends GenericEntity<Person> {
...
}
And then you need the generic repository which should return generic entities not specific persons
public interface GenericRepository extends JpaRepository<GenericEntity, Integer> {
}
which can be called in service as
public List<GenericEntity> findAllGenericEntities() {
return genericRepository.findAll();
}
And then you can also have a person repository
public interface PersonRepository extends JpaRepository<Person, Integer> {
}
which can be called in service as
public List<Person> findAllPersons() {
return personRepository.findAll();
}
I am trying to map DTO to the corresponding #Entity in the service layer.
Condition may be of a set of types: Amount, Title, Date. Each condition, except Amount, has a unique predefined set of clauses.
TitleCondition: includes, startsWith
DateCondition: from, until
The idea is to use common Condition entity with #Inheritance(strategy= InheritanceType.TABLE_PER_CLASS).
The 2 problems I see with this code is:
It is unclear how to properly set data
data type is Object
Is there a way to use convenient Lombok's #Builder with given mapping? What would be the simpler and better way to map dto to entity?
Service:
#Service
public class FilterService {
private Condition convertConditionDtoToEntity(ConditionDto conditionDto) {
Type type = typeRepository.findFirstByName(conditionDto.getType())
.orElseThrow(UnsupportedOperationException::new);
Clause clause;
if (conditionDto.getClause() != null) {
clause = clauseRepository.findFirstByName().orElseThrow(UnsupportedOperationException::new);
}
if (conditionDto.getType().equals("amount")) {
return AmountCondition.builder().type(type).data(???).build();
} else if (conditionDto.getType().equals("title")) {
return TitleCondition.builder().type(type).clause(clause).data(???).build();
} else if (conditionDto.getType().equals("date")) {
return DateCondition.builder().type(type).clause(clause).data(???).build();
} else {
throw new UnsupportedOperationException();
}
}
}
Condition
#Getter
#SuperBuilder
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Inheritance(strategy= InheritanceType.TABLE_PER_CLASS)
public abstract class Condition {
#Id
#GeneratedValue
private long id;
#ManyToOne
private Filter filter;
#Getter
#ManyToOne
public Type type;
public abstract Object getData();
}
DateCondition
#Data
#SuperBuilder
#NoArgsConstructor
#AllArgsConstructor
#Entity
public class DateCondition extends Condition {
#Column
int clauseId;
#Column
#Temporal(TemporalType.DATE)
Date date;
#Getter
#ManyToOne
private Clause clause;
#Override
public Object getData() {
return date;
}
}
TitleCondition
#Data
#SuperBuilder
#NoArgsConstructor
#AllArgsConstructor
#Entity
public class TitleCondition extends Condition {
#Column
int clauseId;
#Column
String title;
#Getter
#ManyToOne
private Clause clause;
#Override
public Object getData() {
return title;
}
}
AmountCondition
#Data
#SuperBuilder
#NoArgsConstructor
#AllArgsConstructor
#Entity
public class AmountCondition extends Condition {
#Column
int amount;
#Override
public Object getData() {
return amount;
}
}
Clause
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#Entity
public class Clause {
#Id
#GeneratedValue
private long id;
#Column
String name;
#OneToMany(mappedBy = "clause")
private Set<Type> types = new HashSet();
}
Type
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
#Entity
public class Type {
#Id
#GeneratedValue
private long id;
#Column
String name;
#ManyToOne
private Clause clause;
#OneToMany(mappedBy = "type")
private Set<Condition> conditions;
}
I have two forms that I use a lot and save a lot of time.
first: transform your model into json and convert the json to object the Mapper class (this link will help https://www.baeldung.com/jackson-object-mapper-tutorial)
second: spring has some cool functions about it. an example would be the BeanUtils.copyProperties function (source, target);
data problem: the data field does not exist for this reason you do not need to set it.
Another problem that I was able to notice is that their properties are all defaulted so set them as private.
I have a object with list of nested object
#Getter
#Setter
#NoArgsConstructor
public class Notification {
private Long id
private Long statusId;
private List <External> external;
}
#Getter
#Setter
#NoArgsConstructor
public class External{
private Long externalId;
private LocalDate date;
}
Dto
#Getter
#Setter
#NoArgsConstructor
public class NotificationPayload {
private Long id;
private Long statusId;
private List <ExternalReferencePayload> external;
}
#Getter
#Setter
#NoArgsConstructor
public class ExternalReferencePayload {
private Long externalReferenceId;
}
Mapper
#Mapper(componentModel = "spring")
public interface NotificationMapper{
public Notification dtoToNotification(NotificationPayload payload);
}
I search the way to map the nested list
In order to perform custom mapping for certain elements it is only needed to define a mapping method and MapStruct will take care of the rest. In your example:
#Mapper(componentModel = "spring")
public interface NotificationMapper{
public Notification dtoToNotification(NotificationPayload payload);
#Mapping(target = "externalId", source = "externalReferenceId")
public External dtoExternal(ExternalReferencePayload payload);
}
With this the nested list will use the dtoExternal mapping method to perform the mapping. With #Mapping you control how the mapping between externalId and externalReferenceId should be done
In my spring-boot project, I have a custom type for ID field of my entity. I can use the type with the help of #Embeddable and #EmbeddedId.
But when I want to add another field with the same type into a single entity, I get a column mapping exception as follows:
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity:
com.example.demo.CarEntity column: id (should be mapped with insert="false" update="false")
CarId class:
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Embeddable
public class CarId implements Serializable {
private String id;
#Override
public String toString() {
return id;
}
}
CarEntity class:
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Entity
public class CarEntity {
#EmbeddedId
private CarId id;
private String name;
private CarId anotherId;
}
Repository class:
#Repository
public interface CarRepository extends JpaRepository<CarEntity, CarId> {
}
application class:
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Bean
CommandLineRunner runner(CarRepository repository) {
return args -> {
CarId carId = new CarId(UUID.randomUUID().toString());
String carName = "a car";
CarEntity carEntity = new CarEntity(carId, carName, carId);
repository.save(carEntity);
repository.findAll().forEach(carEntity1 -> {System.out.println(carEntity1.getId());});
};
}
}
How can I add multiple fields with the same type into the entry class?
The solution I found is to override the field name on anotherId as follows:
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Entity
public class CarEntity {
#EmbeddedId
private CarId id;
private String name;
#Embedded
#AttributeOverride(name="id", column = #Column(name = "anotherId"))
private CarId anotherId;
}