Spring MVC doesn't convert link to entity - java

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?

Related

How to import a CSV file to MSSQL using Springboot

I am working on a project that has a function that allows users to import a file (Excel or CSV) to DB (MsSQL). I have read tutorials on the internet and followed them, but the problem is one of my entities contains an object.
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
#Entity
#Table(name = "question_bank")
public class QuestionBank implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column
private String content;
#Column
private String explanation;
#Column
private String option1;
#Column
private String option2;
#Column
private String option3;
#Column
private String option4;
#Column
private String answer;
#ManyToOne(fetch = FetchType.LAZY, cascade=CascadeType.ALL)
#JoinColumn(name = "status_id")
private Status status;
#ManyToOne(fetch = FetchType.LAZY, cascade=CascadeType.ALL)
#JoinColumn(name = "levelId")
private QuizLevel quizLevel;
The status_id and levelId are from joining other columns of other tables. And this is the code that I use to set the data from Excel file
questionBank.setAnswer(excelData.get(i));
questionBank.setContent(excelData.get(i + 1));
questionBank.setExplanation(excelData.get(i + 2));
questionBank.setOption1(excelData.get(i + 3));
questionBank.setOption2(excelData.get(i + 4));
questionBank.setOption3(excelData.get(i + 5));
questionBank.setOption4(excelData.get(i + 6));
questionBank.setStatus(Integer.valueOf(excelData.get(i + 8)));
questionBank.setCourse(Integer.valueOf(excelData.get(i + 9)));
questionBank.setQuizLevel(Integer.valueOf(excelData.get(i + 10)));
The IDE said the last 3 lines, setStatus, setCourse and setQuizLevel are errors because there are no functions like that in Entity QuestionBank.
How can I do this import, thank you if you are reading and have a solution for me?
For the last object I guess you will have to construct an instance of QuizLevel, fill it with values then pass it to your setter.
I do not know how your csv is structured, but if you isolate the values related to QuizLevel then pass it to your QuestionBank instance;
QuizLevel quizLevel= new QuizLevel();
quizLevel.setValue(myValueFromCsv)
quizLevel.setOtherValue(myOtherValueFromCSV)
questionBank.setQuizLevel(quizLevel);
Same goes for setCourse and setStatus.
You have to make the instance of your Status and Quizlevel object, and after that, you can access or set the values accordingly of these objects. You can't simplily set the value to a object. First create instance of object then the set or get the values associated with that object.
This example might help you properly:
Post post = new Post();
User user = userServiceImpl.getCurrentUser();
post.setTitle(title);
post.setContent(content);
post.setCreatedAt(time);
post.setAuthor(user.getName());
post.setPublishedAt(time);
post.setUpdatedAt(time);
post.setExcerpt(content);
post.setIsPublished(true);
post.setAuthorId(user.getId());
String[] tagsArray = tags.split(" ");
List<Tag> tagList = new ArrayList<Tag>();
for (String tag : tagsArray) {
Tag tagObject = new Tag();
if (tagService.checkTagWithName(tag)) {
tagList.add(tagService.getTagByName(tag));
} else {
tagObject.setName(tag);
tagObject.setCreatedAt(time);
tagObject.setUpdatedAt(time);
tagList.add(tagObject);
}
}
post.setTags(tagList);
postService.savePost(post);
This is my model class for post with a tag object in last:
#Table(name = "posts")
public class Post {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "title")
private String title;
#Column(name = "excerpt")
private String excerpt;
#Column(name = "content",columnDefinition="TEXT")
private String content;
#Column(name = "author")
private String author;
#Column(name = "published_at")
private Timestamp publishedAt;
#Column(name = "is_published")
private Boolean isPublished;
#Column(name = "created_at")
private Timestamp createdAt;
#Column(name = "updated_at")
private Timestamp updatedAt;
#Column(name = "authorId")
private Long authorId;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "post_tags",
joinColumns = {#JoinColumn(name = "post_id" , referencedColumnName = "id")},
inverseJoinColumns = {#JoinColumn(name = "tag_id", referencedColumnName = "id")})
private List<Tag> tags;

Ignore some fields for JSONB Deserialization in Spring JPA

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.

Does the return type of the getter match the parameter type of the setter?

I have two tables\entities that are connected with a forging key.
#Entity
public class SwapEngineReport {
#Id
#Column(name = "FilePath")
private String filePath;
#Column(name = "FileName")
private String fileName;
#Column(name = "LastModifiedDate")
private LocalDate lastModifiedDate;
#Column(name = "LoadedDate")
private LocalDate loadedDate;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "SwapEngineReport2SwapEngineReportType", foreignKey = #ForeignKey(name =
"FK_SwapEngineReport_SwapEngineReportType"))
private SwapEngineReportType swapEngineReportType;
public SwapEngineReportType getSwapEngineReportType() {
return swapEngineReportType;
}
public void setSwapEngineReportType(SwapEngineReportType swapEngineReportType) {
this.swapEngineReportType = swapEngineReportType;
}
#Entity
public class SwapEngineReportType {
#Id
#Column(name = "Type")
private String type;
#Column(name = "Description")
private String description;
During the process stage, I am initiating the SEReport object and setting all the necessary values including the Type object.
#Override
public SwapEngineReport process(Resource resource) throws Exception {
SwapEngineReport swapEngineReport = new SwapEngineReport();
......
SwapEngineReportType type = new SwapEngineReportType();
if(inputReourceValue.equals("dailyex")){type.setType("DAILY_EX");}
if(inputReourceValue.equals("status")) {type.setType("STATUS");}
swapEngineReport.setSwapEngineReportType(type);
return swapEngineReport;
What I don’t understand is why the write method is not working.
This is the error message:
Bean property 'swapEngineReport2swapEngineReportType' is not readable
or has an invalid getter method: Does the return type of the getter
match the parameter type of the setter?
return new JdbcBatchItemWriterBuilder<SwapEngineReport>().beanMapped().dataSource(dataSource)
.sql(environment.getProperty("insertToSwapEngineReport")).build();
And SQL:
INSERT INTO SwapEngineReport
(filePath,fileName,lastModifiedDate,swapEngineReport2swapEngineReportType) VALUES
(:filePath,:fileName,:lastModifiedDate,:swapEngineReport2swapEngineReportType)
Can anyone, please assist me to understand what I am missing.
Thank you

spring.jackson.date-format property does not work properly for the date serialization with #Temporal annotation

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;

JHipster Spring boot : org.hibernate.HibernateException: Unable to access lob stream

I created my app using JHipster. When i try to get list of tournaments via TournamentQueryService i get this error :
Exception in TournamentQueryService.findByCriteria() with cause =
'org.hibernate.HibernateException: Unable to access lob stream' and
exception = 'Unable to access lob stream; nested exception is
org.hibernate.HibernateException: Unable to access lob stream'
This is filter and Page object :
find by criteria : TournamentCriteria{}, page: Page request [number:
0, size 8, sort: startDate: DESC]
So it just gets 8 first tournaments.
This is tournament class :
#Entity
#Table(name = "tournament")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#Document(indexName = "tournament")
public class Tournament extends AbstractAuditingEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#Column(name = "name")
private String name;
#Column(name = "location")
private String location;
#Column(name = "url")
private String url;
#Column(name = "start_date")
private ZonedDateTime startDate;
#Column(name = "end_date")
private ZonedDateTime endDate;
#Column(name = "entry_fee")
private Double entryFee;
#Column(name = "prize")
private Double prize;
#Column(name = "goods")
private String goods;
#Column(name = "favorite_rating")
private Long favoriteRating;
#Column(name = "participants_number")
private Integer participantsNumber;
#Column(name = "finished")
private Boolean finished;
#Column(name = "view_only")
private Boolean viewOnly;
#Column(name = "image")
private String image;
#Column(name = "description")
private String description;
#Column(name = "teams_applied")
private String teamsApplied;
#Lob
#Column(name = "schedule")
private String schedule;
#Lob
#Column(name = "prize_distribution")
private String prizeDistribution;
#Lob
#Column(name = "contacts")
private String contacts;
#Lob
#Column(name = "rules")
private String rules;
#OneToMany(mappedBy = "tournament", fetch = FetchType.LAZY)
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Stream> streams = new HashSet<>();
#ManyToMany(fetch = FetchType.EAGER)
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#JoinTable(name = "tournament_platforms", joinColumns = #JoinColumn(name = "tournaments_id", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "platforms_id", referencedColumnName = "id"))
private Set<Platform> platforms = new HashSet<>();
#ManyToOne
private Game game;
#ManyToOne
private TournamentStatus status;
#ManyToOne(fetch = FetchType.LAZY)
private EntryType entryType;
#ManyToOne(fetch = FetchType.LAZY)
private TournamentFormat format;
#ManyToOne
private Region region;
#ManyToOne(fetch = FetchType.LAZY)
private GameMode gameMode;
#ManyToOne(fetch = FetchType.LAZY)
private PrizeType prizeType;
#ManyToOne
private Organizer organizer;
#ManyToOne(fetch = FetchType.LAZY)
private TournamentStage stage;
#ManyToOne
private HostPlatform hostPlatforms;
#ManyToOne(fetch = FetchType.LAZY)
private TournamentType type;
#ManyToOne
private PlayType playType;
#ManyToOne
private Currency currency;
#ManyToOne
private Country country;
Here is the method that calls hibernate :
#Transactional(readOnly = true)
public Page<Tournament> findByCriteria(TournamentCriteria criteria, Pageable page) {
log.info("find by criteria : {}, page: {}", criteria, page);
final Specifications<Tournament> specification = createSpecification(criteria);
Page<Tournament> result = tournamentRepository.findAll(specification, page);
return result;
}
Is it possibile that you are trying to access Lob properties when hiberante session is closed?
Try to replace your #Lob properties with the following:
#Basic(fetch=FetchType.EAGER) #Lob
and check if the error persists.

Categories

Resources