redisson: Problem to deserialize object with jackson

Hi guys,

I have two applications, one read and another write on redis:

My entity

@Data
@JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
public class Job implements Serializable {
    private static final long serialVersionUID = 1L;
    private String a;
    private String b;
}

For save i use this code:

RList<Job> list = redissonClient.getList(key); list.addAll(jobList);

The value is saved in redis just like that:

{“a”:“test”,“b”:“test”}

My problem is when I try to read the redis list at another java application.

I have a method that use this code to read the list: List<Job> allJobs = redissonClient.getList(key);

But when i execute the project i receive this error:

io.netty.handler.codec.DecoderException: com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Missing type id when trying to resolve subtype of [simple type, class java.lang.Object]: missing type id property ‘@class’ at [Source: (io.netty.buffer.ByteBufInputStream); line: 1, column: 322]

My redisson.json file has the same configuration in both projects:

{ "singleServerConfig": { "idleConnectionTimeout": 10000, "pingTimeout": 1000, "connectTimeout": 10000, "timeout": 3000, "retryAttempts": 3, "retryInterval": 1500, "reconnectionTimeout": 3000, "failedAttempts": 3, "password": null, "subscriptionsPerConnection": 5, "clientName": null, "address": "redis://127.0.0.1:6379", "subscriptionConnectionMinimumIdleSize": 1, "subscriptionConnectionPoolSize": 50, "connectionMinimumIdleSize": 10, "connectionPoolSize": 64, "database": 0, "dnsMonitoringInterval": 5000 }, "threads": 0, "nettyThreads": 0, "codec": null, "useLinuxNativeEpoll": false }

Version of redisson:

<dependency>
    <dependency>
        <groupId>org.redisson</groupId>
        <artifactId>redisson-spring-boot-starter</artifactId>
        <version>3.9.1</version>
    </dependency>

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 18 (13 by maintainers)

Most upvoted comments

@maxhomann I think I understood your requirement correctly: you would like to have minimal class path information to deserialise your ABC class.

Before I go on to explain why Redisson has took the path that leads to where we are now, just imagine in a bazzar senario where someone has asked you to find a file called ABC.txt in a random computer but didn’t tell you in which directory. It would be impossible to find it without scanning/indexing the entire filesystem.

Bear in mind the generic type info is not passed to the JVM runtime, it is easy to see Redisson is facing the same problem when it received a piece of string from Redis and it just says its a type of ABC but god knows which package it is from. So the dilemma of making this to work is whether to ask users to preregister all the class, or should it scan the entire classpath every single time and make a guess when we saw duplicated class names from different packages (you will be surprised to see how many duplicated names), or we just ask the user to write down the names along with their classpath so we know exactly where to look for them.

Redisson took the liberty and choose the latter as the default option. Simply because it requires nothing extra to setup and works for most of the senarios. In particular when the class path is different but shares the same name, as per Java specification dictates, it has be treated as different class.

To recognise the fact that default option cannot cover every single use case, Redisson allows user to customise the codec to suite each ones own needs. This can be done on the global level and/or per key level, it is up to the user to decide.

So there are two solutions:

  1. the fact that projA.ABC and projB.ABC are required to be treated as the same class offends JLS, it is the best to move ABC to a package which are accessible by both projects. Then Jackson/Redisson should work just as normal.
  2. If it is not possible to do above, you need to implement your own convention with or without Jackson and tell Redisson to use this particular way for a given key. Redisson has provided TypedJsonJacksonCodec to simplify the process if you prefer to use Jackson. You can find the usage here: https://github.com/redisson/redisson/blob/365731758f175fbd33cbc3091eadf7d7459179ca/redisson/src/test/java/org/redisson/codec/TypedJsonJacksonCodecTest.java

Hope I have explained everything clearly.

Wow, it finally works! Please excuse me, at the end I was the one that wasn’t clear, because all I wanted to know is your second solution 😌 I’m feeling stupid now, didn’t see that redis.getSet/getMap etc. had overloaded methods where I could provide a codec. To adress your explanation of what happens: I was fully aware of that and agree with you that this should be the default way. Have a nice day!

Since all I needed was serialization/deserialization of multipolygons, I went with my own naïve implementation instead of using geojson-jackson - so problem solved. Thanks for your time though @mrniko 🥇

try to override JsonJacksonCodec.initTypeInclusion method as empty.

Thanks, I was hoping that was a solution, but how to access the object mapper? It doesn’t seem to be accessible via the JsonJacksonCodec instance?

EDIT: The obvious solution when I used my brain: Use the constructor of JsonJacksonCodec to provide my own object mapper instance 👍

if you remove @JsonTypeInfo(use = JsonTypeInfo.Id.NONE) it would work then.