Elasticseach type special #JsonIgnore - java

I have 1 index, 2 types. /spring-boot-1.3.3/
#Document(indexName = "main", type = "item")
#Entity
public class Item {
private Long id;
private String name;
#ManyToOne
private User owner;
}
how can i ignore userData field only for type:"item"
#Document(indexName = "main", type = "user")
#Entity
public class User {
private Long id;
private String userName;
//#JsonIgnore <- ignored for both types, if i add this annotation
private UserData userData; // must be ignored for elastic type: "item"
}

Related

how to map an dto included foreign key id to object one to many relationship

I have an entity like this and when i want to create a new product i want to post also category of id that involves this product.
is any way ta access category by id ...i try to create a constructor to category with id as param but this does not solve my problem
#Entity
#Data
#Table(name="products")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name="name")
private String name;
#Column(name="description")
private String description;
#Column(name="base64Image")
private String base64Image;
#Column(name="price")
private Double price;
#ManyToOne(fetch = FetchType.EAGER,cascade =CascadeType.ALL)
#JoinColumn(name = "category_id")
private Category category;
#ManyToOne
#JoinColumn(name="discount_id",referencedColumnName = "id")
private Discount discount;
#OneToMany(mappedBy = "product")
private Set<ProductLocation> productLocations;
#CreationTimestamp
#Column(name="created_at")
private LocalDateTime created_at;
#UpdateTimestamp
#Column(name="updated_at")
private LocalDateTime updated_at;
}
I have this dto but when using mapstruct category id of product created remains null`
#Data
public class ProductRequestDto {
private String name;
private String description;
private String base64Image;
private Double price;
private Long categoryId;
#JsonIgnore
private Discount discount=null;
}
the mapper interface that i have used
#Mapper(componentModel = "spring")
public interface ProductMapper {
ProductMapper INSTANCE = Mappers.getMapper(ProductMapper.class);
List<ProductResponseDto> productToDto(List<Product> products);
Product dtoToProduct(ProductRequestDto product);
ProductResponseDto productToDto(Product product);
void update(#MappingTarget Product product, ProductRequestDto productDto);
}
can you suggest any solution
For me best option is to
change mapper to be abstract class instead interface adding annotation to it
#Mapper(componentModel = "spring")
adding #Mapping(target = "Category", source = "categoryId") to productToDto method
Autowiring categoryRepository to Mapper
and creating custom method for mapping from id to Entity
public Category resolveCategory(Long categoryId) {
if (categoryId == null) {
return null;
}
return categoryRepository.getById(categoryId);
}

How to get object from OneToMany collection of objects?

I have an Order entity and OrderProduct. I want to show order details on frontend and of course order products in it. So how to fetch product object in OrderProduct JSON. I'm missing product object in products array. I don't need order object one more time and i think it going to be a infinite recursion stuff with it. :)
My Order entity:
#Entity
#Getter
#Setter
#Table(name ="orders")
public class Order{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Long id;
private BigDecimal totalPrice;
#OneToMany(mappedBy = "order", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JsonManagedReference(value="orders")
private List<OrderProduct> products = new ArrayList<>();
private int userId;
#DateTimeFormat(pattern="dd/MM/yyyy")
private Date date = new Date();
#DateTimeFormat(pattern="dd/MM/yyyy")
private Date deliveryDate;
#Enumerated(EnumType.STRING)
private OrderType orderType;
}
My OrderProduct entity:
#Entity
#Setter
#Getter
public class OrderProduct {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.EAGER)
#JsonBackReference(value="product")
#JoinColumn(name = "product_id")
private Product product;
#ManyToOne
#JsonBackReference(value="orders")
#JoinColumn(name = "order_id")
private Order order;
private Integer quantity;
}
Product entity:
#Entity
#Getter
#Setter
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(unique = true)
private String name;
private double price;
#OneToMany(mappedBy = "product", cascade = CascadeType.ALL)
#JsonManagedReference(value="ingredients")
private List<Ingredient> ingredients = new ArrayList<>();
#OneToMany(mappedBy = "product",fetch = FetchType.EAGER)
#JsonManagedReference(value="product")
private List<OrderProduct> products = new ArrayList<>();
private String fileName;
}
This can help annotate one of your entity clases with
#JsonIdentityInfo(
property = "id",
generator = ObjectIdGenerators.PropertyGenerator.class
)
Every time when JSON serialization go in circles object data will be replaced with object id or orher field of entity for your choose.
You can use #JsonViewannotation to define the fields that you need to serialize to JSON
How it works:
You need define class with interfaces. For example:
public class SomeView {
public interface id {}
public interface CoreData extends id {}
public interface FullData extends CoreData {}
}
Mark entity fields with #JsonView(<some interface.class>)
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#JsonView(SomeView.id.class)
private Long id;
#Column(nullable = false)
#JsonView(SomeView.CoreData.class)
private String username;
#Column(nullable = false)
#JsonView(SomeView.FullData.class)
private String email;
}
Annotate endpoint with #JsonView(<some interface.class>)
#GetMapping()
#JsonView(<some interface.class>)
public User getUser() {
return <get user entity somwhere>
}
In case #JsonView(SomeView.id.class) you will get this JSON:
{
id: <some id>
}
In case #JsonView(SomeView.CoreData.class):
{
id: <some id>,
username: <some username>
}
In case #JsonView(SomeView.FullData.class):
{
id: <some id>,
username: <some username>,
email: <some email>
}
#JsonView also works with embeded objects and you can annotate one field with multiply views classes - #JsonView({SomeView.FullData.class, SomeOtherView.OtherData.class})
In your case i think you should annotate all the fields you need except:
#OneToMany(mappedBy = "product",fetch = FetchType.EAGER)
#JsonManagedReference(value="product")
private List<OrderProduct> products = new ArrayList<>();
in Product
to avoid circular serialization
Or as alternative you can just use DTO classes or seralize oject to JSON manualy (https://thepracticaldeveloper.com/java-and-json-jackson-serialization-with-objectmapper/)
This can be done by my library beanknife
// This configure generate a class named ProductInfo which has the same shape with Product without property "products"
#ViewOf(value = Product.class, genName="ProductInfo", includePattern = ".*", excludes = {"products"})
class ProductInfoConfigure {}
// This configure generate a class named OrderProductRelation with the same shape of OrderProduct.
// But it has not order property and the type of its product property is change to ProductInfo generated above.
#ViewOf(value = OrderProduct.class, genName="OrderProductRelation", includePattern = ".*", excludes = {"order"})
class OrderProductRelationConfigure {
#OverrideViewProperty("product")
private ProductInfo product;
}
// This configure generate a class named OrderDetail with the same shape of Order.
// But the type of its products property is change to List<OrderProductRelation>
#ViewOf(value = Order.class, genName="OrderDetail", includePattern = ".*")
class OrderDetailConfigure {
#OverrideViewProperty("products")
private List<OrderProductRelation> products;
}
will generate these classes:
class ProductInfo {
private Long id;
private String name;
private double price;
private List<Ingredient> ingredients; // it is not processed because you have not provide the class Ingredient
private String fileName;
}
public class OrderProductRelation {
private Long id;
private ProductInfo product;
private Integer quantity;
}
public class OrderDetail {
public Long id;
private BigDecimal totalPrice;
private List<OrderProductRelation> products;
private int userId;
private Date date = new Date();
private Date deliveryDate;
private OrderType orderType;
}
Then
Order order = ...
OrderDetail orderDetail = OrderDetail.read(order);
// serialize the otherDetail instead of order.
List<Order> orders = ...
List<OrderDetail> orderDetails = OrderDetail.read(orders);
// serialize the orderDetails instead of orders.
Possible problems:
I doesn't use Lombok, so Lombok may need to be adapted because it change the byte code on the fly. But it is not a big problem, I will try to adapt it if someone commit the issue and provide enough use cases.
The generated class does not inherit the annotation on the original class. In next release I will provide a sulotion. At this moment, as a workaround, we can use custom method to convert the property manually. such as
#ViewOf(value = Order.class, genName="OrderDetail", includePattern = ".*")
class OrderDetailConfigure {
#OverrideViewProperty("products")
private List<OrderProductRelation> products;
#OverrideViewProperty("orderType")
public static String orderType(Order source) {
return source.getOrder().name();
}
}
The generated class will be changed to
public class OrderDetail {
public Long id;
private BigDecimal totalPrice;
private List<OrderProductRelation> products;
private int userId;
private Date date = new Date();
private Date deliveryDate;
private String orderType;
}
Update
Version 1.2.0 released. Add support of annotation inheritance.
#ViewOf(value = Order.class, genName="OrderDetail", includePattern = ".*")
#UseAnnotation({DateTimeFormat.class, Enumerated.class, JsonProperty.class})
class OrderDetailConfigure {
#OverrideViewProperty("products")
private List<OrderProductRelation> products;
}
generate
public class OrderDetail {
public Long id;
private BigDecimal totalPrice;
private List<OrderProductRelation> products;
private int userId;
#DateTimeFormat(pattern="dd/MM/yyyy")
private Date date;
#DateTimeFormat(pattern="dd/MM/yyyy")
private Date deliveryDate;
#Enumerated(EnumType.STRING)
private OrderType orderType;
}

#GetMapping used to retrive item gives a responce of infinite loop of foreignkey object

i am new in spring boot and i could not find solution for this for a day now.
#GetMapping used to retrive item gives a responce of infinite loop of foreignkey object "user".
why am i getting this infinite loop?
how to fix it?
user object in infinite loop(the problem)
result that i want
item entity
#Entity
public class Item{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long ItemId;
#ManyToOne
#JoinColumn(name = "owner_id")
private User user;
private String ItemName;
// #Column(columnDefinition="text")
private String Description;
private double Price;
private int AvailableQuantity;
private double shippingWeight;
// #Transient
// private MultipartFile Picture;
#Enumerated(value = EnumType.STRING)
private Category category;
#OneToMany(mappedBy = "item")
#JsonIgnore
private List<CartItem> CartItemList;
}
user entity
#Entity
#Table(name = "Utilisateur")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idU;
private String username;
private String password;
private String firstname;
private String lastname;
private String gender;
private Long phone;
private String adress;
#Temporal(TemporalType.DATE)
private Date dateofbirth;
private int rating;
private String email;
public Role role;
private Integer status;
#OneToMany(mappedBy = "user")
private List<Item> ItemList;
}
item service
#Service
public class ItemService implements ItemServiceInterface{
#Autowired
ItemRepository itemrepository;
public Optional<Item> getItemById(long id){
return itemrepository.findById(id);
}
}
item controller
#RestController
public class ItemControl {
#Autowired
ItemServiceInterface itemservice;
#GetMapping("/getitem/{id}")
public Optional<Item> getitembyid(#PathVariable Long id) {
return itemservice.getItemById(id);
}
}
You can use combination of #JsonManagedReference and #JsonBackReference to discourage Jackson from infinite serialization.
#Entity
#Table(name = "Utilisateur")
public class User {
// omitted
#JsonManagedReference
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Item> ItemList;
}
#Entity
public class Item{
// omitted
#JsonBackReference
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "owner_id")
private User user;
}
More details could be found here https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion
You can make use of lazy loading to cut the dependency loop between user and item. However, following that approach might potentially affect other parts of your projects because other codes might use the entity with an assumption that item list in user entity is already eager fetched.
A better way is not return the entity object directly to the REST response. You can define a data model for the rest response and convert the entity to that model in your service class. This way, you can completely control what to return and not to.
Another approach if you still want to use the entity as response: https://www.baeldung.com/spring-data-jpa-named-entity-graphs. This way, you can define when to use the lazy load with each specific query.

Can't save entity with composite key

I get an exception when I try to save entities when composite key is used. Here is the exception, models and repository I try to save to. Can anyone help?
org.springframework.beans.TypeMismatchException: Failed to convert
property value of type 'org.CheckType_$$_jvst96c_4' to required type
'int' for property 'checkType'; nested exception is
java.lang.IllegalArgumentException: Cannot convert value of type
'org.CheckType_$$_jvst96c_4' to required type 'int' for property
'checkType': PropertyEditor
[org.springframework.beans.propertyeditors.CustomNumberEditor]
returned inappropriate value of type 'org.CheckType_$$_jvst96c_4'
#Entity
public class CheckType {
#Id
private int id;
#NotNull
private String name;
#OneToMany(mappedBy = "checkType")
private List<ClientCheck> checks;
//getters and setters
}
#Entity
public class Offer {
#Id
#Column(name = "offerid")
private Integer offerId;
//...
#OneToMany(mappedBy = "offer")
private List<ClientCheck> clientCheckList;
//getters and setters
}
#Entity
#IdClass(ClientCheckId.class)
public class ClientCheck {
#Id
#ManyToOne
#JoinColumn(name = "offer_id", referencedColumnName = "offerid")
private Offer offer;
#Id
#ManyToOne
#JoinColumn(name = "check_type_id", referencedColumnName = "id")
private CheckType checkType;
#Id
private Date timestamp;
private String result;
//getters and setters
}
public class ClientCheckId implements Serializable {
private int offer;
private int checkType;
private Date timestamp;
//getters and setters
//equals and hashCode
}
public interface ClientCheckRepo extends JpaRepository<ClientCheck, ClientCheckId> {
}
If another entity is a part of composite key, you must declare that entity in your ID class, not its ID:
public class ClientCheckId implements Serializable {
private int offer;
private CheckType checkType;
private Date timestamp;
//getters and setters
//equals and hashCode
}
The error message is quite readable if you want how Hibernate works: org.CheckType_$$_jvst96c_4 is the enriched version of your class, which Hibernate tries to assign to checkType field of ClientCheckId via reflection, and fails because of type incompatibility.

Spring JPA mapping - first steps

I have class User:
#Entity
public class User {
#Id
#GeneratedValue
private Integer id;
private String name;
private String password;
#ManyToMany
#JoinTable
private List<Role> roles;
}
Class Owner inherits from User
#Entity
public class Owner extends User {
private String pesel;
private String adress;
#OneToMany(cascade={CascadeType.PERSIST, CascadeType.REMOVE})
private List<Pet> pets;
}
and Owner had Pet
public class Pet {
#Id
#GeneratedValue
private Integer id;
private String name;
private String weight;
#ManyToOne
private Owner owner;
}
Why when starting the application gets the error:
org.springframework.data.mapping.PropertyReferenceException: No
property user found for type Pet!
--EDIT
First I have version, which was as follows:
now I try to share User instance to a doctor and the owner of the animal
The problem is that I do not know whether I am doing the mapping , and therefore wanted to ask whether it must look like
--edit2
I've simplified the scheme just a bit to better illustrate what happens
--edit3
Currently my Object's was presented:
#Entity
public class Pet {
#Id
#GeneratedValue
private Integer id;
private String name;
private String weight;
}
User
#Entity
public class User {
#Id
#GeneratedValue
private Integer id;
private String name;
private String password;
#ManyToMany
#JoinTable(name="user_roles")
private List<Role> roles;
}
PetOwner
#Entity
public class PetOwner extends User {
private String pesel;
private String adress;
#OneToMany(mappedBy="petOwner")
private List<Pet> pets;
}
I replace
#ManyToOne
private PetOwner petOwner;
for
#ManyToOne
private Owner petOwner;
and it works. Do you have a PetOwner class?
Also provide the log error to get more information about it

Categories