JsonMappingException: Can not construct instance of - spring

I have an entity with two columns refering same column in other table. Basically, a Transaction depends on Account: when creating a new transaction a send money from one account to another.
Account:
#Entity
#Table(name = "accounts")
public class Account implements java.io.Serializable {
private static final long serialVersionUID = 2612578813518671670L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "idaccount", unique = true, nullable = false)
private Long idaccount;
#Column(name = "name", length = 50)
private String name;
#NotNull
#ManyToOne
#JoinColumn(name = "iduser")
private User user;
...
Transaction:
#Entity
#Table(name = "transactions")
public class Transaction {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "idtransaction", unique = true, nullable = false)
private Long idtransaction;
private BigDecimal amount;
#NotNull
#ManyToOne
#JoinColumn(name = "SOURCE_ACCOUNT")
private Account sourceAccount;
#NotNull
#ManyToOne
#JoinColumn(name = "TARGET_ACCOUNT")
private Account targetAccount;
...
TransactionController
#CrossOrigin
#RestController
#RequestMapping("/transaction")
public class TransactionController {
#Autowired
TransactionService transactionService;
#RequestMapping(method = RequestMethod.POST)
public ResponseEntity<Transaction> addTransaction(#RequestBody Transaction Transaction) {
transactionService.save(Transaction);
return new ResponseEntity<Transaction>(Transaction, HttpStatus.CREATED);
}
...
If I try post to create a transaction (naturally I have the accounts already created):
{
"amount": 111,
"sourceAccount": 1,
"targetAccount": 2
}
I get:
Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: Could not read document: Can not construct instance of com.mycompany.basicbank.model.Account: no int/Int-argument constructor/factory method to deserialize from Number value (1)
at [Source: java.io.PushbackInputStream#63447acf; line: 3, column: 18] (through reference chain: com.mycompany.basicbank.model.Transaction["sourceAccount"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.mycompany.basicbank.model.Account: no int/Int-argument constructor/factory method to deserialize from Number value (1)
at [Source: java.io.PushbackInputStream#63447acf; line: 3, column: 18] (through reference chain: com.mycompany.basicbank.model.Transaction["sourceAccount"])
So my question is: what should I check in order to fix "Can not construct instance of com.livingit.basicbank.model.Account: no int/Int-argument constructor/factory method to deserialize from Number"?

The problem is the json you are sending doesn't exactly match the Transaction class. hence you see the error.
But what you are trying to achieve is a valid scenario and can be done.
Some options.
Create a new class(not Transaction) which matches the json. Like
class TransactionClient {
BigDecimal amount,
Long sourceAccount,
Long targetAccount
}
And in the backend(controller or some in service) you can get the Acccounts from database with this sourceAccount and targetAccount and create a transaction object with this objects and save.
From the frontend call backend to get the Accounts(json) for these source and target accounts and then call your transaction endpoint with the json like this
{
"amount": 111,
"sourceAccount": {
"idaccount" :123123,
..... // All the Non Null fields
},
"targetAccount": {
"idaccount" :45554,
..... // All the Non Null fields
},
}

Related

Not able to join 2 tables in spring data jpa

I am new to spring-data-jpa. I am working on a task management system.
I have 2 entities:
public class Task {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long taskId;
private String title;
private String description;
private Status status;
#OneToOne
#JoinColumn(name = "user_id", referencedColumnName = "userId")
private User assignee;
and:
#Entity
#Table(name = "tbl_user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long userId;
private String name;
private String email;
private Active active;
private String password;
}
I have an endpoint that creates a new task:
#PostMapping
#ResponseStatus(HttpStatus.CREATED)
public TaskResponse addTask(#Valid #RequestBody Task task){
return taskService.addTask(task);
}
This is the implementation:
#Override
public TaskResponse addTask(Task task) {
taskRepository.save(task);
return mapToTaskResponse(task);
}
The error I get when I send a request is:
2023-01-24 15:10:01.825 WARN 1961 --- [nio-8080-exec-4] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `com.tasksmanagement.entity.User` (although at least one Creator exists): no int/Int-argument constructor/factory method to deserialize from Number value (1); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.tasksmanagement.entity.User` (although at least one Creator exists): no int/Int-argument constructor/factory method to deserialize from Number value (1)<EOL> at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 5, column: 17] (through reference chain: com.tasksmanagement.entity.Task["assignee"])]
I am not sure what am I doing wrong. Basically I create a user and send the id of this user in the request (the assignee field in the payload - screenshot attached) in order to assign the new task to that user.
Can anyone please assist and help me understand what is the issue with the request?
Should I send something else instead of the userId?
Thank you
assignee is of type User not Integer, and yet you are sending assignee:1 which fails the deserialization of your request.
it should be rather
assignee:{ userId:1 }
but it will fail anyway on later on during atempt to persist the Task (but that is a different issue)
So basically you want to create a Task for a User who has an id of 1.
All you need to do is map you User object with your Task object.
Try the following
#Override
public TaskResponse addTask(Task task) {
User assignee = new User();
assignee.setUserId(task.assignee);
task.setAssignee(assignee);
taskRepository.save(task);
return mapToTaskResponse(task);
}

Map parent to Child with different column names JPA

I am using Springboot 2.5.2 with JPA
I am trying to map a parent child table but they have different names in the actual DB.
My parent Entity class looks ass follows
#Entity
#Table(name="PARENTTABLE")
public class ParentEntity implements Serializable
{
private static final long serialVersionUID = -8610605997974967804L;
#Id
#Column(name = "PID")
private int pId;
#Column(name = "COL_ID_0")
private String colId_0;
#Column(name = "DATA1")
private String data1_0;
#Column(name = "DATA2")
private String data2_0;
//Joining Entity/Table
#OneToMany(targetEntity = ChildEntity.class,
cascade = CascadeType.ALL)
#JoinColumn(name = "COL_IDD",
referencedColumnName = "COL_ID_0")
private List<ChildEntity> childenity;
// ..getters and Setters
and my Child Entity/Table
#Entity
#Table(name="CHILDRENTABLE")
public class ChildEntity implements Serializable
{
private static final long serialVersionUID = -2781104466439391315L;
#Id
#Column(name="CID")
private int cId;
#Column(name="COL_IDD")
private String colIdd;
#Column(name = "DETIALS1")
private String datai1_1;
#Column(name = "DETIALS2")
private String datai1_2;
// ..getters and setters
How do you link these two entity classes with each other to display the Parent and details?
With the above configurations I get the Parent data back but the child records does not display only containing null in the Api call.
#JensSchauder Sorry meant to say the endpoint from the controller class. The database is exactly setup as the above example (not the real names) the Parent class contains the header data and the child class contains the details of the parent.
I need to call the end point for the parent entity and then it should list the child data along with it. as per the below example
JSON result I am expecting
'[
{
"pId": 2,
"colId_0": "5555",
"data1_0": "6001363000007",
"data2_0": "6001001392709",
"childenity": [{"cId": 222,
"colIdd": "5555",
"datai1_1": "Data222",
"datai1_2": "Data222"
},
{"cId": 333,
"colIdd": "5555",
"datai1_1": "Data333",
"datai1_2": "Data333"
}
]
}
]'
But I get the following
[
{
"pId": 2,
"colId_0": "5555",
"data1_0": "6001363000007",
"data2_0": "6001001392709",
"childenity": "null"
}
]

How to prevent saving of referred entity when using #IdClass?

I have two entities, Type and TypeValue. Each Type can have several TypeValues. While trying to persist a new TypeValue, I get a database error that Type already exists (which is correct, but I don't want to add it again, I want to add just a new 'TypeValue'). I have similar classes without IdClass that are working, so I assume that either the #IdClass definition is wrong or I forgot to define something so that the referred object is not updated.
How to prevent saving of the referred entity Type when using #IdClass for TypeValue?
Class definitions:
#Entity
#Table(name = "TYPE", schema = "VOC")
public class Type implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "TYPEID")
private String typeID;
#Column(name = "NAME")
private String name;
#OneToMany(mappedBy = "type")
private List<TypeValue> listTypeValue;
// constructor, getter, setter, equals, hashcode, ...
}
#Entity
#IdClass(TypeValueID.class)
#Table(name = "TYPE_VALUE", schema = "VOC")
public class TypeValue implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#ManyToOne
#JoinColumn(name = "TYPEID")
#ForeignKey(name = "TYPEVALUE_FK")
private Type type;
#Id
#Column(name = "VALUE")
private String value;
// constructor, getter, setter, equals, hashcode, ...
}
public class TypeValueID implements Serializable {
private static final long serialVersionUID = 1L;
String type;
String value;
// equals, hashcode
}
Example of usage:
Type type = ... // get existing type with typeID "DETAIL"
Session session = sessionFactory.getCurrentSession();
TypeValue newTypeValue = new TypeValue(type, "new value");
session.save(newTypeValue);
session.flush();
Thrown exception:
SEVERE: Servlet.service() for servlet [spring] in context with path [/project] threw exception [Request processing failed; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement] with root cause
org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "type_pkey"
Detail: Key (typeid)=(DETAIL) already exists.
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2455)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2155)
...
please change your String typeID to int or long. Then use #GeneratedValue for auto-increment.
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private int typeID ;
Check this example
#Entity
#Table(name = "USERS")
#Proxy(lazy = false)
public class User {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private int uID ;
private String uName ;
private String uEmail ;
private String uPassword;
#OneToMany(cascade=CascadeType.ALL,fetch = FetchType.EAGER)
private List<Reminder> uReminders = new ArrayList<>();
Next Entity
#Entity
#Proxy(lazy = false)
public class Reminder {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private int reminderID ;
private Date reminderDate ;
private String reminderDescription ;
You have defined the foreign key column with #Id.
#Id
#ManyToOne
#JoinColumn(name = "TYPEID")
#ForeignKey(name = "TYPEVALUE_FK")
private Type type;
So it is expecting unique value in the column "type".Hope this may help.
The type attribute in the TypeValueID class is wrong, the class should look like this:
public class TypeValueID implements Serializable {
private static final long serialVersionUID = 1L;
Type type;
String value;
// equals, hashcode
}
The JPA Persistence API 2.1 documentation states:
The names of the fields or properties in the primary key class and the
primary key fields or properties of the entity must correspond and
their types must match according to the rules specified in Section
2.4, “Primary Keys and Entity Identity” and Section 2.4.1, “Primary Keys Corresponding to Derived Identities”.
And the rule that applies in this case is:
If the composite primary key class is represented as an id class, the
names of primary key fields or properties in the primary key class and
those of the entity class to which the id class is mapped must
correspond and their types must be the same.

converting URI to entity with custom controller in spring data rest?

i have an jpa entity like this.
#Entity
#Table(name = "location")
#Data
public class Location {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "LOCATION_ID", unique = true)
#NotEmpty(message = "Please Enter Location ID")
private String name;
#Column(name = "LOCATION_DESCRIPTION")
#NotEmpty(message = "Please Enter Location Description")
private String description;
#ManyToOne
#NotNull(message = "Please Choose a Building")
Building building;
#Version
Long version;
}
and the repository like this.
public interface LocationRepository extends PagingAndSortingRepository<Location, Long> {
Location findByName(#Param("name") String name);
}
i am using spring data rest i am able to create location with rest api by providing the following payload
{
"name":"adminxxxxx","description":"adminxxx" , "building": "http://localhost:8080/buildings/2"
}
now i am trying to write my custom controller which will persist the entity. this is my custom controller
#ExposesResourceFor(Location.class)
#RepositoryRestController
#BasePathAwareController
public class LocationController {
#Autowired
LocationRepository locationDao;
#Autowired
LocationResourceAssembler resourceAssembler;
#Value("${buildings.error.messages.uniqueconstraintviolation}")
String uniqueConstrainMessage;
static final String TAG = LocationController.class.getSimpleName();
#RequestMapping(value="locations",method = org.springframework.web.bind.annotation.RequestMethod.POST)
public ResponseEntity<?> save(#RequestBody #Valid Location location) {
try {
location = locationDao.save(location);
LocationResource b = resourceAssembler.toResource(location);
return ResponseEntity.ok().body(b);
} catch (DataIntegrityViolationException e) {
if (locationAlreadyExists(location.getName()))
throw new LocationAlreadyExistException(uniqueConstrainMessage, location);
else
throw new RuntimeException("Some Error Occured");
}
}
i am getting this error
exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.alamdar.model.Building: no String-argument constructor/factory method to deserialize from String value ('http://localhost:8080/buildings/2')
at [Source: java.io.PushbackInputStream#5d468b16; line: 3, column: 60] (through reference chain: com.alamdar.model.Location["building"])</div></body></html>
can anyone please help?
I am not sure why you are writing a custom controller however the issue would appear to be that you do not have a default no args constructor so Jackson cannot instantiate an instance.
This is because you are using Lombok's #Data annotation:
https://projectlombok.org/features/Data.html
You should also annotate you class with #NoArgsConstructor to have a default no-args constructor generated:
#Entity
#Table(name = "location")
#Data
#NoArgsConstructor
public class Location {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(name = "LOCATION_ID", unique = true)
#NotEmpty(message = "Please Enter Location ID")
private String name;
#Column(name = "LOCATION_DESCRIPTION")
#NotEmpty(message = "Please Enter Location Description")
private String description;
#ManyToOne
#NotNull(message = "Please Choose a Building")
Building building;
#Version
Long version;
}

Add entity with OneToOne Relation using JPA and REST

I am using Spring JPA Restful, and I don't understand how to insert an entity with a foreign key.
Activity Entity:
#Entity
#Table(name= "Activity")
public class Activity implements Serializable{
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name="uuid", strategy = "uuid2")
#Column(name = "uuid", nullable = false, unique = true)
private UUID uuid;
#OneToOne(fetch = FetchType.EAGER, cascade=CascadeType.MERGE)
#JoinColumn(name="type", nullable = false)
private ActivityType type;
#Column(nullable = false)
private String label;
ActivityType Entity:
#Entity
#Table(name= "ActivityType")
public class ActivityType implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#Column(nullable = false, unique = true)
private String code;
#Column(nullable = false
private String label;
Is it possible to insert Activity simply? With something like this JSON where ActivityType's id "1" exists:
createActivity:
{"label":"LABEL","type":1}
With this code I have to do:
createActivity:
{"label":"LABEL","type":{"id":1}}
which return value is:
{
"uuid": "a54b27aa-8d49-41fd-8976-70c019c40e3b",
"type": {
"id": 1,
"code": null,
"label": null
},
"label": "LABEL",
"details": null
}
I use the library gson for parsing domain classes into JSON.
//... code for making your activity, let's say you have an Activity object myActivity
Just add the following code where you want to parse your object into JSON.
Gson gson = new GSON();
String json = gson.toJson(myActivity);

Resources