Reputation: 115
I've tried many different solutions and nothing is working. Here is what I have right now:
My data will look like this for a Player:
{
"id": 1,
"name": "Stalker",
"type": "dark",
"faction": 3,
"weaponAbilities": {
"normal": [
5,
1,
0
],
"dark": [
4,
2,
8
]}
}
I'm trying to map the abilities.
Here's my code:
@Data
@Entity
@Table(name = "player")
@EntityListeners(AuditingEntityListener.class)
public class Player {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
@OneToMany
Map<String, Abilities> weaponAbilities;
}
and then:
@Data
@Entity
@Table(name = "abilities")
@EntityListeners(AuditingEntityListener.class)
public class Abilities {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
@ElementCollection(targetClass = Integer.class )
private List<Integer> ability;
}
the error I get:
Caused by: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `com.project.myapp.entity.Abilities` out of START_ARRAY token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `com.project.myapp.entity.Abilities` out of START_ARRAY token
at [Source: (PushbackInputStream); line: 1, column: 1067708] (through reference chain: java.lang.Object[][911]> com.project.myapp.entity.Player["weaponAbilities"]->java.util.LinkedHashMap["normal"])
Upvotes: 1
Views: 1435
Reputation:
Firstly the error is JSON, not JPA, so if you mean this question to fix that, then restate it.
I answer here how you can Map classes in JPA to be able to persist a field of that type. Since you haven't defined how you want to persist that information in the database, one way you can do it without the need for an artificial entity containing the List<Integer>
is as follows
@Entity
public class Player
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
@CollectionTable
@ElementCollection
@Convert(attributeName="value",converter=ListIntegerStringConverter.class)
Map<String, List<Integer>> weaponAbilities;
}
This will then store the Map field into a separate table, with key stored in a VARCHAR column, and value stored in a VARCHAR column. You can control the size of these columns if you need to in the normal JPA ways. The List<Integer>
can be stored as comma-separated, or JSON, or whatever into this value column. For example, using comma-separated
@Converter(autoApply=true)
public class ListIntegerStringConverter implements AttributeConverter<List<Integer>, String>
{
public String convertToDatabaseColumn(List<Integer> attribute)
{
if (attribute == null)
{
return null;
}
StringBuilder str = new StringBuilder();
for (Integer val : attribute)
{
if (str.length() > 0)
{
str.append(",");
}
str.append(val);
}
return str.toString();
}
public List<Integer> convertToEntityAttribute(String dbData)
{
if (dbData == null)
{
return null;
}
List<Integer> list = new ArrayList<>();
StringTokenizer tokeniser = new StringTokenizer(dbData, ",");
while (tokeniser.hasMoreTokens())
{
list.add(Integer.valueOf(tokeniser.nextToken()));
}
return list;
}
}
But it all depends on what your requirements are for this List, whether you are likely to have huge numbers of elements in it, whether you want to query it, and so on, and that can have an impact on whether you would use an intermediate entity, or do it into a single column (as shown here).
Upvotes: 1
Reputation: 423
Try using:
private Map<String, List<Integer>> ability;
Because you're trying to map:
{
"normal": [
5,
1,
0
]
}
Upvotes: 0