FasterXML / FasterXML/jackson-databind

Map Key interface not serialized with both type serializer or keyUsing

Open
#3,119 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
3.7k
Forks
1.5k
Avg merge
3d 6h
Merged PRs (30d)
28

Description

**Describe the bug**

In my application I have a `Map` where `KapuaId` is an interface, and has its own serializer (since I also use this type in other parts as a standalone object):

```
public class KapuaIdSerializer extends JsonSerializer {

@Override
public void serialize(KapuaId value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeString(value.toCompactId());
}

}
```

So, I first thought that registering the mixin for the standalone type would have also worked when serializing the `Map`:

```
objectMapper = new ObjectMapper();
objectMapper.addMixIn(KapuaId.class, KapuaIdMixin.class);
```

```
@JsonDeserialize(using = KapuaIdDeserializer.class)
@JsonSerialize(using = KapuaIdSerializer.class)
public interface KapuaIdMixin { }
```

But unfortunately it's not, since the `toString()` of the concrete type is returning:

```
{
"1": null,
"5667511473135966782": false,
"8466406404189434576": false
}
```

So I built a container object, where I used `@JsonValue` and `@JsonSerialize(keyUsing = KapuaIdSerializer.class)`, but nothing changed:

```
public class IsJobRunningMapResponse {

private final Map map;

public IsJobRunningMapResponse(Map map) {
this.map = map;
}

@JsonValue
@JsonSerialize(keyUsing = KapuaIdSerializer.class)
public Map getMap() {
return map;
}

}
```

But the result was the same. In the end I had to use a Converter for the whole container type, basically duplicating what `KapuaIdSerializer` was already doing:

```
public class IsJobRunningMapResponseSerializer extends JsonSerializer {

@Override
public void serialize(IsJobRunningMapResponse value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeStartObject();
for (Map.Entry entry : value.getMap().entrySet()) {
if (entry.getValue() == null) {
gen.writeNullField(entry.getKey().toCompactId());
} else {
gen.writeBooleanField(entry.getKey().toCompactId(), entry.getValue());
}
}
gen.writeEndObject();
}
```

And in the end the response was the one I expected, with `KapuaId` serialized correctly:

```
// KapuaId value coming from KapuaId.toCompactId()

{
"AQ": null,
"TqcLqDS4Wj4": false,
"dX63xIXNstA": false
}
```

So... I found a workaround, but I think that something is not ok with the key type serialization.

**Version information**
2.12.2

**To Reproduce**
If you have a way to reproduce this with:

Steps reproduced above. Full repository at https://github.com/lorthirk/kapua/tree/feature-multipleJobIsRunning/job-engine/app/resources/src/main/java/org/eclipse/kapua/job/engine/app

**Expected behavior**
`KapuaId` should have been serialized with its own serializer, or at least `keyUsing` should not have been ignored

**Additional context**
Using together with Jersey 2.23.2

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.