I have multiple objects in my array using . If I then send this to my Spring Boot backend with axios and output the FormData beforehand, I get the following image. That fits. In the backend, however, I need this list of objects as an entity. In this case, of type List. Do I do that?
Frontend code:
let data = new FormData();
...
data.append("zugeordnet", JSON.stringify(personNamen));
await axios.post("/neuerEintrag", data,...)
React:
Backend:
#PostMapping("/neuerEintrag")
public String neuerEintrag(HttpServletRequest req,#RequestParam("zugeordnet") List<?> zugeordnet,..) {
List<User> userListe = (List<User>) zugeordnet;
for(User inListe : userListe) //ERROR here
{
System.out.println("USER :" + inListe);
}
...
}
java.lang.ClassCastException: class java.lang.String cannot be cast to class com.home.calendar.User.User
UPDATE
For completeness, here is the user entity and the complete method for a new entry.
#PostMapping("/neuerEintrag")
public String neuerEintrag(HttpServletRequest req, #RequestParam("beschreibung") String beschreibung,
#RequestParam("datum") Date datum, #RequestBody List<User> zugeordnet,
#RequestBody List<Freunde> kontaktAuswahl, #RequestParam("neuAlt") String neuAlt,
#RequestParam("kalenderId") int kalenderId) { }
The User Entity:
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
#JsonIgnoreProperties("user")
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "user")
private List<Kalender> kalenderEinträge;
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(String name, List<Kalender> kalenderEinträge) {
super();
this.name = name;
this.kalenderEinträge = kalenderEinträge;
}
public List<Kalender> getKalenderEinträge() {
return kalenderEinträge;
}
[getter/setter]
Spring can't parse an unknown object.
To get it work, I suggest a new class for the "request".
#Data // lombok - this generates getter/setters/equals/hashcode for you
public class NeuerEintragRequest {
private List<User> zugeordnet;
private String beschreibung;
private int kalendarId;
// and your others fields
}
The controller can now use very type-safe objects.
#PostMapping("/neuerEintrag")
public String neuerEintrag(#RequestBody NeuerEintragRequest request) {
for(User user : request.getUserlist()) {
// a logging framework is a lot better. Try to use log4j or slf4j.
log.info("USER: {}", user);
}
...
}
Typescript
Let axios handle the typing and serializing. See this tutorial: https://masteringjs.io/tutorials/axios/post-json
To post all the needed data, you can create a new object.
// no formdata - just send the object
const data = { zugeordnet: personNamen, kalendarId: 123, beschreibung: 'abc' };
await axios.post("/neuerEintrag", data);
You can also create a interface in typescript, but this is going to much for a stackoverflow-answer. Try to learn more about spring and typescript.
Based on question & comments ,
your front end call data.append("zugeordnet", JSON.stringify(personNamen)); is converting your object to List<String> instead of List<User>.
So you can transform this List<String> to List<User> in your postMapping:
#PostMapping("/neuerEintrag")
public String neuerEintrag(HttpServletRequest req,#RequestParam("zugeordnet") List<?> zugeordnet,..) {
ObjectMapper mapper=new ObjectMapper();
for(String str:zugeordnet){
System.out.println(mapper.readValue(str, User.class));
}
...
}
Related
public class UserList {
private String id;
private String email;
private String userType;
private String rolls;
private String partner;
private Integer customersLinked;
private String position;
private String status;
#Autowired
ICustomerRepository customerRepository;
public UserList (Users user){
this.id = user.getId();
this.email = user.getEmail();
this.userType = user.getUserType();
this.rolls = user.getRolls();
this.partner = user.getPartner();
List<Customer> customersLinked = customerRepository.findAllByLinkedUsersIn(user.getId());
this.customersLinked = 0;
this.position = user.getPosition();
this.status =user.getStatus();
}
//Getter and Setter
}
This class is used as a list in the frontEnd ,get specific data ,not send all the data
#RequestMapping(value = "usersLinked/{id}/{type}", method = RequestMethod.GET)
public Object getUsersLinkedById(#PathVariable("id") String id,#PathVariable("type") Integer type) {
List<String> users = null;
switch (type) {
case 0:
users = usersRepository.findAll().stream().map(m -> m.getId()).collect(Collectors.toList());
break;
}
//Add userList
List<UserList> userList = new ArrayList<>();
if(users != null)
{
users.forEach(userId ->
{
Optional<Users> user = this.usersRepository.findById(userId);
userList.add(new UserList(user.get()));
});
}
return userList;
}
}
As you can see from above I am calling al the data from the user repository and sending it the list
My customer repository
public interface ICustomerRepository extends MongoRepository<Customer, String> {
Customer findByBusinessInformation_businessName(String businessName);
List<Customer> findByBusinessInformation_partnerAssigned(String partnerAssigned);
#Query("{ 'LinkedUsers' : ?0 }")
Customer findByLinkedUsers(String id);
List<Customer> findAllByLinkedUsersIn(String id);
}
In the userList I get the error when I add the logic wityh the customerRepository ,without the repository there everything is working(Want to use the repository to get an array of customer and then get the size() of the array and add it to linkedCustomers). Am I missing sommething
You are trying to inject the field customerRepository using Autowired annotation, but your class is not injectable.
You can add an annotation #Repository on your class UserList
Or use constructor injection (better way to inject your beans)
You're probably missing the #repository annotation on top of your repository class.
Another unrelated word of advice:
In your controller you use findAll and filter in java to keep only the ids.
Then you go to the same repository and perform another query per user-id from above.
This is a causing you to create multiple database calls which are one of the most expensive operations you can do, when you already have all your data from the first single query...
Also if you're only looking at the bottom part of the function you don't event need a query per each user-id (when you have a list of user ids as input), you can create a query that uses the 'in' convention and pass a list of user-ids to create a single db call.
First of all I would get rid of #Autowired ICustomerRepository customerRepository; in UserList class. It doesn't belong there. The counting of linked customers should be executed in ICustomerRepository and the result to be passed into UserList via the constructor.
e.g.
public class UserList {
private String id;
private String email;
private String userType;
private String rolls;
private String partner;
private Long customersLinked; //better use Long instead of Integer
private String position;
private String status;
// constructor takes the number of linked customers as parameter
public UserList (Users user, Long customersLinked ) {
this.id = user.getId();
this.email = user.getEmail();
this.userType = user.getUserType();
this.rolls = user.getRolls();
this.partner = user.getPartner();
this.customersLinked = customersLinked;
this.position = user.getPosition();
this.status =user.getStatus();
}
//Getter and Setter
}
and then create the count query in ICustomerRepository
e.g.
public interface ICustomerRepository extends MongoRepository<Customer, String> {
//other methods
Long countByLinkedUsersIn(String id); //not so sure if this query works in mongo
}
and finally in your controller
Optional<Users> user = this.usersRepository.findById(userId);
Long count = this.usersRepository.countByLinkedUsersIn(userId);
userList.add(new UserList(user.get(), count));
P.S. I have a doubt for the query method: Long countByLinkedUsersIn(String id);. Usually when repository methods have "In" in their names, countByLinkedUsersIn, then it is expected as parameter a List and not a single user id. However if your previous method List<Customer> findAllByLinkedUsersIn(String id); worked for you, then this one should work too.
I am trying to insert items in a list in a database as single values in rows with the name of the sender. I am able to send the payload and insert into a single row with the user detailst. How can I loop through the payload sent and insert all the items into individual rows? I have tried to look for examples no luck. So far I can only insert as a single row in the database
this is the payload
{"labsigned":["234568","234567","2345678","2344556","12335677","2345677","234556","234545"]}
My controller
#RequestMapping(path = "/labreport/createrordispatched", method = RequestMethod.POST)
public ResponseEntity<?> createDispatched(#RequestBody Dispatched dispatched){
if(labDashboardService.createDispatched(dispatched)) {
return ResponseEntity.status(HttpStatus.CREATED).body(true);
}
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(false);
}
My Service
public boolean createDispatched(Dispatched dispatched) {
dispatched.setCreatedBy(getCurrentUserEmail());
dispatched.setDateCreated(System.currentTimeMillis());
Dispatched ticket = new Dispatched(
dispatched.getCreatedBy(),
dispatched.getDateCreated(),
dispatched.getlabsigned()
);
dispatchedRepository.save(ticket);
return false;
}
My Model
#Entity
#Table(name = "DISPATCHED")
public class Dispatched {
private String id;
private String labsigned;
private Long dateCreated;
private String createdBy;
public Dispatched(){}
public Dispatched(String createdBy, Long dateCreated, String labsigned){
this.labsigned = rorlabsigned;
this.dateCreated = dateCreated;
this.createdBy = createdBy;
}
Assuming that you were able to insert all labsigned in the payload into one single row with the code you mentioned in the question, You should iterate dispatched.labsigned and insert one by one as rows to accomplish what you need. And returning false at the end of method createDispatched will always return HttpStatus.BAD_REQUEST even though the records are successfully saved in the DB, so you might need to change it to return true.
public boolean createDispatched(Dispatched dispatched) {
List<Dispatched> newTickets = new ArrayList<>();
dispatched.setCreatedBy(getCurrentUserEmail());
dispatched.setDateCreated(System.currentTimeMillis());
for(String labSigned:dispatched.getlabsigned()){
Dispatched ticket = new Dispatched(
dispatched.getCreatedBy(),
dispatched.getDateCreated(),
labSigned
);
newTickets.add(ticket);
}
dispatchedRepository.saveAll(newTickets);
return true;
}
Just send in a list of those values. Shouldn't have to be wrapped in a named field on an object. Just send it in as a json array like ["234568","234567","2345678","2344556","12335677","2345677","234556","234545"]. In your controller method, body don't pass it in as Dispatched but instead a List and then just loop through those creating a list of Dispatch objects and then using saveAll in the repository passing in the newly created Dispatched list.
Update: Example without actually compiling. Should be good enough for the example. Also using lombok to make it easier to read and a few other updates.
#AllArgsConstructor
#FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
#RestController
public class DispatchController {
DispatchedEntityFactory dispatchedEntityFactory;
DispatchedRepository dispatchedRepository;
#PostMapping("/labreport/createrordispatched")
public ResponseEntity<Boolean> createDispatched(DispatchedRequest dispatchedRequests){
List<DispatchedEntity> dispatchedEntities = dispatchedEntityFactory.creatMultipleFromDispatchRequest(dispatchedRequests);
if(CollectionUtils.isEmpty(dispatchedEntities)) {
return ResponseEntity.badRequest().body(false);
}
dispatchedRepository.saveAll(dispatchedEntities);
return ResponseEntity.ok(true);
}
}
#Value
public class DispatchedRequest {
String id;
List<String>labsigned;
Long dateCreated;
String createdBy;
}
#Entity
#Table(name = "DISPATCHED")
#Data
#FieldDefaults(level = AccessLevel.PRIVATE)
public class DispatchedEntity {
String id;
String labsigned;
Long dateCreated;
String createdBy;
}
#Component
public class DispatchedEntityFactory {
public List<DispatchedEntity> creatMultipleFromDispatchRequest(final DispatchedRequest dispatchedRequest) {
List<DispatchedEntity> dispatchedEntities = new ArrayList<DispatchedEntity>();
for(String labsignature : dispatchedRequest.getLabsigned()) {
DispatchedEntity dispatchedEntity = new DispatchedEntity(dispatchedRequest.getId(),labsignature, dispatchedRequest.getDateCreated(), dispatchedRequest.getCreatedBy());
dispatchedEntities.add(dispatchedEntity);
}
return dispatchedEntities;
}
}
I'm a newbie coder having just finished a 6 month coding crash-course. I'm working on a java webapp to demonstrate my skills, and the project idea I had involves retrieving JSON data from an API, something we didn't learn about in class. I made POJOs to match the JSON, and I'm trying to parse the JSON into java objects to store in a database, however my database tables are never filled with data when I run through the app. I suspect the problem is somewhere with my method to convert the JSON but any feedback is greatly appreciated. Here's all my code I think is relevant, sorry if its TMI. I also apologize if my code is ugly, I'm a beginner... Thanks!
API returns JSON like this:
{
"result":{
"status":1,
"num_results":1,
"total_results":500,
"results_remaining":499,
"matches":[{
"match_id":3188095188,
"match_seq_num":2784956606,
"start_time":1495079320,
"lobby_type":7,
"radiant_team_id":0,
"dire_team_id":0,
"players":[{
"account_id":86920222,
"player_slot":0,
"hero_id":18
},{
"account_id":61122568,
"player_slot":1,
"hero_id":85
},{
"account_id":10208661,
"player_slot":2,
"hero_id":13
},{
"account_id":106083675,
"player_slot":132,
"hero_id":50
}]
}]
}
}
My POJOs:
#Entity
#JsonIgnoreProperties(ignoreUnknown = true)
public class Result {
#JsonIgnore
#Id
#GeneratedValue
private int id;
#JsonProperty("status")
private int status;
#JsonProperty("num_results")
private int num_results;
#JsonProperty("total_results")
private int total_results;
#JsonProperty("results_remaining")
private int results_remaining;
#OneToMany
#JoinColumn(name = "result_id")
#ElementCollection(targetClass=Matches.class)
#JsonProperty("matches")
private List<Matches> matches;
// getters and setters
}
#Entity
#JsonIgnoreProperties(ignoreUnknown = true)
public class Matches {
#Id
#JsonProperty("match_id")
private int match_id;
#JsonIgnore
#ManyToOne
private Result result;
#JsonProperty("match_seq_num")
private int match_seq_num;
#JsonProperty("start_time")
private int start_time;
#JsonProperty("lobby_type")
private int lobby_type;
#JsonProperty("radiant_team_id")
private int radiant_team_id;
#JsonProperty("dire_team_id")
private int dire_team_id;
#OneToMany
#JoinColumn(name = "Matches_id")
#ElementCollection(targetClass=Players.class)
#JsonProperty("players")
private List<Players> players;
// getters and setters
}
#Entity
#JsonIgnoreProperties(ignoreUnknown = true)
public class Players {
#JsonIgnore
#Id
#GeneratedValue
private int id;
#JsonIgnore
#ManyToOne
private Matches matches;
#JsonProperty("account_id")
private int account_id;
#JsonProperty("player_slot")
private int player_slot;
#JsonProperty("hero_id")
private int hero_id;
// getters and setters
}
Services method to read and convert the JSON to objects (url is censored, don't want my API key to be public)
public class SteamService {
public static Result getMatchHistory(String steamid){
Result result = new Result();
String MatchHistoryUrl = "https:**URL**="+steamid;
RestTemplate restTemplate = new RestTemplate();
Result jsonresult = restTemplate.getForObject(MatchHistoryUrl, Result.class);
return jsonresult;
}
}
Controller
#Controller
#RequestMapping("")
public class HomeController {
#Autowired
private ResultsDao resultsDao;
#RequestMapping(value = "", method = RequestMethod.GET)
public String index(Model model){
model.addAttribute("title", "Welcome");
return "home/home";
}
#RequestMapping(value = "", method = RequestMethod.POST)
public String processSteamIdField(#RequestParam("steamid")String steamid, Model model) {
Result newresult = getMatchHistory(steamid);
resultsDao.save(newresult);
return "redirect:results";
}
}
DAO
#Repository
#Transactional
public interface ResultsDao extends CrudRepository<Result, Integer>{
}
Maybe my approach is a bit naive, but... If you want to store the JSON as string in the database, then I would use an object mapper for this:
new ObjectMapper().writeValueAsString(myObject);
and for reading a JSON and parsing it to a class I would do:
new ObjectMapper().readValue(JSON_STRING_HERE, "utf-8"), MyPOJO.class);
Also, if you already are using Spring, then your controller may look like this (for a POST, for example)
#RequestMapping(value = "/", method = RequestMethod.POST)
public MyPojo myController(#RequestBody MyPojo myBody) {
myRepository.save(myBody);
}
So, the parsing of the JSON that the client is sending to your app and your controller is already handled by Spring
Currently I'm working on spring project and I want to display class as a JSON response. Following is the class template and other related details.
public class Country {
#Column(name = "name")
private String name;
#Id
#Column(name = "code")
private String Code;
//Getters & Setters ...
}
current response :
[{"name":"Andorra","code":"AD"},{"name":"United Arab Emirates","code":"AE"}]
Expected response :
[ { "countries" : [{"name":"Andorra","code":"AD"},{"name":"United Arab Emirates","code":"AE"}], "status" : "ok", "message":"success", etc..etc...}]
instead of status and message, it could be some array list too.
You need create class contain list and use ResponseEntity.
public class Foo {
private List<Country> countries;
// get/set...
}
#Controller
public class MyController {
#ResponseBody
#RequestMapping(value = "/foo", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET)
public ResponseEntity<Foo> foo() {
Foo foo = new Foo();
Country country = new Country();
foo.getCountries().add(country);
return ResponseEntity.ok(foo);
}
}
You should create another object, e.g. called Countries as shown below:
public class Countries {
private List<Country> countries;
// getters & setters
}
or:
public class Countries {
private Country[] countries;
// getters & setters
}
The list or array of Country objects will map to your expected {"countries" : [{"name":"Andorra","code":"AD"},{"name":"United Arab Emirates","code":"AE"}]}, because the JSON {} refers to some object and [] refers to list/array in Java code.
Actually you can also achieve using jackson library.
//Create obj of ObjectMapper
ObjectMapper mapper = new ObjectMapper();
//Get the Json string value from the mapper
String json = mapper.writeValueAsString(obj)
And then return this json string in your controller method.
The advantage of using this is that, you can also ignore certain fields in the POJO for JSON conversion using #JsonIgnore annotation (Put this annotation before the getter of the field that you want to ignore) (Not sure if you can do the same from Spring ResponseEntity.
Note: Please correct me if I am wrong anywhere.
We have a big table with a lot of columns. After we moved to MySQL Cluster, the table cannot be created because of:
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 14000. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs
As an example:
#Entity #Table (name = "appconfigs", schema = "myproject")
public class AppConfig implements Serializable
{
#Id #Column (name = "id", nullable = false)
#GeneratedValue (strategy = GenerationType.IDENTITY)
private int id;
#OneToOne #JoinColumn (name = "app_id")
private App app;
#Column(name = "param_a")
private ParamA parama;
#Column(name = "param_b")
private ParamB paramb;
}
It's a table for storing configuration parameters. I was thinking that we can combine some columns into one and store it as JSON object and convert it to some Java object.
For example:
#Entity #Table (name = "appconfigs", schema = "myproject")
public class AppConfig implements Serializable
{
#Id #Column (name = "id", nullable = false)
#GeneratedValue (strategy = GenerationType.IDENTITY)
private int id;
#OneToOne #JoinColumn (name = "app_id")
private App app;
#Column(name = "params")
//How to specify that this should be mapped to JSON object?
private Params params;
}
Where we have defined:
public class Params implements Serializable
{
private ParamA parama;
private ParamB paramb;
}
By using this we can combine all columns into one and create our table. Or we can split the whole table into several tables. Personally I prefer the first solution.
Anyway my question is how to map the Params column which is text and contains JSON string of a Java object?
You can use a JPA converter to map your Entity to the database.
Just add an annotation similar to this one to your params field:
#Convert(converter = JpaConverterJson.class)
and then create the class in a similar way (this converts a generic Object, you may want to specialize it):
#Converter(autoApply = true)
public class JpaConverterJson implements AttributeConverter<Object, String> {
private final static ObjectMapper objectMapper = new ObjectMapper();
#Override
public String convertToDatabaseColumn(Object meta) {
try {
return objectMapper.writeValueAsString(meta);
} catch (JsonProcessingException ex) {
return null;
// or throw an error
}
}
#Override
public Object convertToEntityAttribute(String dbData) {
try {
return objectMapper.readValue(dbData, Object.class);
} catch (IOException ex) {
// logger.error("Unexpected IOEx decoding json from database: " + dbData);
return null;
}
}
}
That's it: you can use this class to serialize any object to json in the table.
The JPA AttributeConverter is way too limited to map JSON object types, especially if you want to save them as JSON binary.
You don’t have to create a custom Hibernate Type to get JSON support, All you need to do is use the Hibernate Types OSS project.
For instance, if you're using Hibernate 5.2 or newer versions, then you need to add the following dependency in your Maven pom.xml configuration file:
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-52</artifactId>
<version>${hibernate-types.version}</version>
</dependency>
Now, you need to declare the new type either at the entity attribute level or, even better, at the class level in a base class using #MappedSuperclass:
#TypeDef(name = "json", typeClass = JsonType.class)
And the entity mapping will look like this:
#Type(type = "json")
#Column(columnDefinition = "json")
private Location location;
If you're using Hibernate 5.2 or later, then the JSON type is registered automatically by MySQL57Dialect.
Otherwise, you need to register it yourself:
public class MySQLJsonDialect extends MySQL55Dialect {
public MySQLJsonDialect() {
super();
this.registerColumnType(Types.JAVA_OBJECT, "json");
}
}
And, set the hibernate.dialect Hibernate property to use the fully-qualified class name of the MySQLJsonDialect class you have just created.
If you need to map json type property to json format when responding to the client (e.g. rest API response), add #JsonRawValue as the following:
#Column(name = "params", columnDefinition = "json")
#JsonRawValue
private String params;
This might not do the DTO mapping for server-side use, but the client will get the property properly formatted as json.
It is simple
#Column(name = "json_input", columnDefinition = "json")
private String field;
and in mysql database your column 'json_input' json type
There is a workaround for those don't want write too much code.
Frontend -> Encode your JSON Object to string base64 in POST method, decode it to json in GET method
In POST Method
data.components = btoa(JSON.stringify(data.components));
In GET
data.components = JSON.parse(atob(data.components))
Backend -> In your JPA code, change the column to String or BLOB, no need Convert.
#Column(name = "components", columnDefinition = "json")
private String components;
In this newer version of spring boot and MySQL below code is enough
#Column( columnDefinition = "json" )
private String string;
I was facing quotes issue so I commented below line in my project
#spring.jpa.properties.hibernate.globally_quoted_identifiers=true
I had a similar problem, and solved it by using #Externalizer annotation and Jackson to serialize/deserialize data (#Externalizer is OpenJPA-specific annotation, so you have to check with your JPA implementation similar possibility).
#Persistent
#Column(name = "params")
#Externalizer("toJSON")
private Params params;
Params class implementation:
public class Params {
private static final ObjectMapper mapper = new ObjectMapper();
private Map<String, Object> map;
public Params () {
this.map = new HashMap<String, Object>();
}
public Params (Params another) {
this.map = new HashMap<String, Object>();
this.map.putAll(anotherHolder.map);
}
public Params(String string) {
try {
TypeReference<Map<String, Object>> typeRef = new TypeReference<Map<String, Object>>() {
};
if (string == null) {
this.map = new HashMap<String, Object>();
} else {
this.map = mapper.readValue(string, typeRef);
}
} catch (IOException e) {
throw new PersistenceException(e);
}
}
public String toJSON() throws PersistenceException {
try {
return mapper.writeValueAsString(this.map);
} catch (IOException e) {
throw new PersistenceException(e);
}
}
public boolean containsKey(String key) {
return this.map.containsKey(key);
}
// Hash map methods
public Object get(String key) {
return this.map.get(key);
}
public Object put(String key, Object value) {
return this.map.put(key, value);
}
public void remove(String key) {
this.map.remove(key);
}
public Object size() {
return map.size();
}
}
HTH
If you are using JPA version 2.1 or higher you can go with this case.
Link Persist Json Object
public class HashMapConverter implements AttributeConverter<Map<String, Object>, String> {
#Override
public String convertToDatabaseColumn(Map<String, Object> customerInfo) {
String customerInfoJson = null;
try {
customerInfoJson = objectMapper.writeValueAsString(customerInfo);
} catch (final JsonProcessingException e) {
logger.error("JSON writing error", e);
}
return customerInfoJson;
}
#Override
public Map<String, Object> convertToEntityAttribute(String customerInfoJSON) {
Map<String, Object> customerInfo = null;
try {
customerInfo = objectMapper.readValue(customerInfoJSON,
new TypeReference<HashMap<String, Object>>() {});
} catch (final IOException e) {
logger.error("JSON reading error", e);
}
return customerInfo;
}
}
A standard JSON object would represent those attributes as a HashMap:
#Convert(converter = HashMapConverter.class)
private Map<String, Object> entityAttributes;