I have a Spring JPA Model
#Entity
#Table(name = "projects")
#TypeDefs({ #TypeDef(name = "jsonb", typeClass = JsonBinaryType.class) })
public class Project implements Serializable {
#Id
private long id;
#Column(name = "version_id")
private Long version;
#Column(name = "created_by")
private String createdBy;
#Column(name = "created_at")
private LocalDateTime createdAt;
#Column(name = "updated_by")
private String updatedBy;
#Column(name = "updated_at")
private LocalDateTime updatedAt;
#Column(name = "is_archived")
private Boolean archived;
private String commentsRoomId;
private String workflowType;
private String workflowId;
#Type(type = "jsonb")
#Column(columnDefinition = "jsonb")
private Map<String, ProjectSection> sections;
Now the data in the last property is a JSONB Property which should ignore some of the fields. as it wouldnt be present in the DB either.
Now when I try to get the data I get the following error.
The given Json object value: {s06=ProjectSection(version=1, enabled=true, type=milestones, values={}, visibility=null, sectionId=null, sectionSchema=null)
which says this after the json repr.
Now my Section looks like
#NoArgsConstructor
#AllArgsConstructor
#Data
public class ProjectSection {
#JsonProperty("version_id")
private Long version;
#JsonProperty("enabled")
private Boolean enabled;
#JsonProperty("type")
private String type;
#JsonProperty("values")
private Map<String, ProjectField> values;
#JsonProperty("visibility")
private List<String> visibility;
// Not Srtored in DB
#JsonIgnore
#Transient
private String sectionId;
#JsonIgnore
#Transient
private ProjectTemplate.SectionSchema sectionSchema;
I think maybe because of it being in a JSONB Nested fields the transient doesn't make sense.
How should I make sure these values are ignored when its deserialising from the DB and loads properly.
If I remove these extra fields, it seems to work.
Why don't you use some mappers ModelMapper or DozerMapper to handle such cases.
Related
In my spring boot application I have 3 Entities, meetingSetting, meetingDate and time. MeetingSettingsId is referenced in both entities date and time. time also have dateId as a reference. I know want to send such a json to my backend:
{
"meetingName":"hallo",
"meetingUrl":"",
"meetingPw":"s",
"dates":"2021-05-30",
"times":[
{
"startTime":"15:30",
"endTime":"16:30"
},
{
"startTime":"18:30",
"endTime":"19:30"
}
]
}
But I am getting the following error:
not-null property references a null or transient value : com.cbc.coorporateblinddateservice.entities.times.Time.meetingDate
I want to save with one method meetingSetting witht the shown json.
This is how my entities look:
#Entity
#Table(name = "meeting_date")
#Data
public class Date {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "meeting_date")
private String date;
#OneToMany(mappedBy = "meetingDate", cascade = CascadeType.ALL)
private List<Time> meetingTime = new ArrayList<>();
#ManyToOne()
#JoinColumn(name = "meeting_settings_name", nullable = false)
private MeetingsSetting meetingsSetting;
#JsonCreator
public static Date fromDateAsString(String dateString){
Date date = new Date();
date.setDate(dateString);
return date;
}
}
meetingSettingEntity:
#Entity
#Table(name = "meeting_settings")
#Data
public class MeetingsSetting {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "meeting_name")
private String meetingName;
#Column(name = "meeting_url")
private String meetingUrl;
#Column(name = "meeting_pw")
private String meetingPw;
#OneToMany(mappedBy = "meetingsSetting", cascade = CascadeType.ALL)
private Date dates = new Date();
#OneToMany(mappedBy = "meetingsSetting", cascade = CascadeType.ALL)
private List<Time> times = new ArrayList<>();
}
and finally time:
#Entity
#Table(name = "meeting_times")
#Data
public class Time {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "start_time")
private String startTime;
#Column(name = "end_time")
private String endTime;
#ManyToOne()
#JoinColumn(name = "meeting_settings_name", nullable = false)
private MeetingsSetting meetingsSetting;
#ManyToOne()
#JoinColumn(name = "meeting_date_id")
private Date meetingDate;
}
this is the save method I am using and here probably the error occurs. I guess I kind of have to tell to save time and date too if I am not wrong, but I did not know how to do it the service method calls the save from a jparepository:
#PostMapping("/")
public void saveMeeting(#RequestBody MeetingsSetting meetingsSetting){
meetingSettingService.saveMeeting(meetingsSetting);
}
The problem with your implementation is that you are providing dates field as a String, but in the backend model it's represented as Object of type Date.
You have to make sure your backend model represent your json, by for example introduce DTOs ( Data Transfert Object ) that matches your json model and then map to your entities.
However, if you are just developing this application for tests or as a proof of concept. Here a working solution, just add this method in your Date.java class :
#JsonCreator
public static Date fromDateAsString(String dateString){
Date date = new Date();
date.setDate(dateString);
return date;
}
The idea here is to help Jackson (which is the library responsible for deserializing json to Java Object) to create a Date Instance from the String provided in json.
I'm working on a project using Spring Data JPA and Hibernate and one of my entities has a pretty weird behaviour: it's not saving some of the properties. The code below is my model class. It has some more properties and but all of them are String with the columnDefinition="TEXT". Debugging the object I'm sending to the repository all properties have values in it, get and set methods are working fine, etc.. but it only saves the title.
Now comes the weird part, if I do this Column(name = "isbn_v", columnDefinition="TEXT") it saves the data normally. The same for all columns that are not saving. I don't understand why. Model class:
#Entity
#Table(name = "notice")
public class Notice implements Serializable {
private static final long serialVersionUID = 4521230269805147556L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "seq_no", nullable = false, updatable = false)
private Integer id;
#Column(name = "title", columnDefinition="TEXT")
private String title;
#Column(name = "isbn", columnDefinition="TEXT")
private String isbn;
#Column(name = "issn", columnDefinition="TEXT")
private String issn;
#Column(name = "author", columnDefinition="TEXT")
private String author;
#Column(name = "publisher", columnDefinition="TEXT")
private String publisher;
// get / set
}
Repository class:
public interface NoticeRepository extends JpaRepository<Notice, Integer>, JpaSpecificationExecutor<Notice> {
#Override
#Modifying
#Transactional
Notice save(Notice notice);
}
Any clue of what I'm doing wrong?
I have the following property in application.properties file:
spring.jackson.date-format=yyyy-MMM-dd
There is object definition to be serialized:
public class InjuryDTO {
private Long id;
private String kindOfInjury;
private String muscle;
private String side;
private Integer outOfTraining;
private Date injuryDate;
private Long athleteId;
// getters and setters are omitted for brevity }
This is class from which InjuryDTO object is originally created:
#Entity
#Table(name = "INJURY")
public class Injury {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "INJURY_ID")
private Long id;
#Column(name = "KIND_OF_INJURY")
private String kindOfInjury;
#Column(name = "MUSCLE")
private String muscle;
#Column(name = "SIDE")
private String side;
#Column(name = "OUT_OF_TRAINING")
private Integer outOfTraining;
#Temporal(value = TemporalType.DATE)
#Column(name = "INJURY_DATE")
private Date injuryDate;
#ManyToOne
#JoinColumn(name = "ATHLETE_ID")
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private Athlete athlete;
// get,set-ters are removed for brevity
}
So, if the deserialization of this JSON property happens:
"injuryDate":"2018-Jun-02"
Jackson accepts this string and transforms it to the corresponding java.util.Date object, but when serialization happens with no commented #Temporal(value = TemporalType.DATE) annotation then server gets back the following JSON property: "injuryDate":"2018-06-02".
Question is: Why #Temporal annotation affects the actual representation of the date property in JSON?
Try this one:
#Temporal(TemporalType.DATE)
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
#Column(name="INJURY_DATE")
private Date injuryDate;
I have a mapped entity in SpringData/Jpa
#AllArgsConstructor(suppressConstructorProperties = true)
#Data
#Entity
#Builder
#Table(name = "requests")
#ToString
#NoArgsConstructor
public class Request {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String externalId;
#Enumerated(EnumType.STRING)
private DataSource dataSource;
private String requestNumber;
private Date requestDate;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "CLIENTID")
private Client clientId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="DESTINATIONPOINTID")
private Point destinationPointId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "MARKETAGENTUSERID")
private User marketAgentUserId;
private String invoiceNumber;
private Date invoiceDate;
private String documentNumber;
private Date documentDate;
private String firma;
private String storage;
private String contactName;
private String contactPhone;
private String deliveryOption;
#Temporal(TemporalType.TIMESTAMP)
private Date deliveryDate;
private Integer boxQuantity;
private Integer weight;
private Integer volume;
private BigDecimal goodsCost;
#Temporal(TemporalType.TIMESTAMP)
#JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd.MM.yyyy HH:mm")
private Date lastStatusUpdated;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "LASTMODIFIEDBY")
private User lastModifiedBy;
#Enumerated(EnumType.STRING)
private RequestStatus requestStatusId;
private String commentForStatus;
private Integer hoursAmount;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name= "ROUTELISTID")
private RouteList routeListId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "LASTVISITEDROUTEPOINTID")
private Point lastVisitedRoutePointId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "WAREHOUSEPOINTID")
private Point warehousePoint;
#OneToMany(mappedBy = "requestId")
private List<RequestHistory> requestHistory = new ArrayList<>();
}
I also have a complex POST-request with many parameters, but i boiled problem down to this:
Some part of this stack (Hibernate, Jackson-databind, Spring-MVC/REST/Data) is unable to map a String (A link to the entity) into the entity itself:
#RequestMapping(value = "/commands/updateRequests", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
public void Fgsfds(
#RequestBody Request request
) {}
I pass a String (A proper link to an entity) to it from let's say, Postman, and it returns an error with message:
"message": "JSON parse error: Cannot construct instance of `org.springframework.hateoas.Resource` (although at least one Creator exists): no String-argument
constructor/factory method to deserialize from String value ('http://localhost:8080/api/requests/8'); nested exception is
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `org.springframework.hateoas.Resource` (although at least one Creator
exists): no String-argument constructor/factory method to deserialize from String value ('http://localhost:8080/api/requests/8')\n at [Source: (
PushbackInputStream); line: 1, column: 1]",
I'm quite baffled with this conundrum.
What could possibly be wrong?
I have following JPA entity:
Entity
#Entity
#Table(name = "todo")
#NamedEntityGraph(name = "TodoEntity.children",
attributeNodes = #NamedAttributeNode("children"))
public class TodoEntity {
public TodoEntity() {
}
#Id
#GeneratedValue
private Long id;
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
private Long userId;
private String text;
private String description;
private Boolean collapsed;
private Boolean completed;
private Integer sortOrder;
private Date expiredDate;
#CreationTimestamp
#Temporal(TemporalType.TIMESTAMP)
private Date creationDate;
private Integer priority;
private String guid;
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
#JsonIgnore
#Column(updatable = false,nullable = false)
private Long parentId;
#OneToMany(fetch = FetchType.EAGER)
#Cascade({CascadeType.ALL})
#Fetch(FetchMode.JOIN)
#JoinColumn(name = "parentId", referencedColumnName = "id")
#OrderBy("sortOrder ASC")
private List<TodoEntity> children;
}
Repo
#EntityGraph(value = "TodoEntity.children", type = EntityGraph.EntityGraphType.FETCH)
Page<TodoEntity> findByUserIdAndParentId(Long userId, Long parentId, Pageable pageable);
I want to have a TodoList that I can infinitely nest.
The code is working so far - only thing is that when I have around 1500 todos and they are nested, SQL and the queries are becoming slow (around 1,3s)
How can I improve this?
IDEA:
Actually I think it would be enough to just get all Todos in the database with one query (that takes 2,2 ms) and then nesting them with java (having the parentId) so that the workload is on the application layer.