Java Cassandra Datastax 驱动程序自定义编解码器不处理集合类型

Java Cassandra Datastax driver custom codec not handling collection types

我以教程为参考定义了一个自定义编解码器- https://docs.datastax.com/en/latest-java-driver/java-driver/reference/customCodecs.html。这是我的编解码器实现:-

    package org.questqa.server.database.codecs;

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;

import org.questqa.server.database.fetchers.UserInfoFetcher;
import org.questqa.server.entity.User;
import org.springframework.beans.factory.annotation.Autowired;

import com.datastax.driver.core.DataType;
import com.datastax.driver.core.ProtocolVersion;
import com.datastax.driver.core.TypeCodec;
import com.datastax.driver.core.exceptions.InvalidTypeException;

public class UserCodec extends TypeCodec<User>
{

    @Autowired
    UserInfoFetcher userFetcher;

    public UserCodec(DataType cqlType, Class<User> javaClass) 
    {
        super(cqlType, javaClass);
    }

    @Override
    public User deserialize(ByteBuffer buffer, ProtocolVersion arg1) `throws InvalidTypeException {`
        // TODO Auto-generated method stub
        System.out.println("Executing deserialize");
        User user = new User();
        try {
            System.out.println("Size of ByteBuffer: " + `buffer.array().length);`
            String userId = new String(buffer.array(), "UTF-8");
            System.out.println("User id to set: " + userId);
            System.out.println("Setting user id...");
            user.setUserId(userId);
            System.out.println("User id set: " + user.getUserId());
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return user;
    }
    @Override
    public String format(User user) throws InvalidTypeException 
    {
        System.out.println("Executing format");
        return user.getUserId();
    }
    @Override
    public User parse(String userId) throws InvalidTypeException 
    {
        // TODO Auto-generated method stub
        System.out.println("Executing parse");
        User user = new User();
        user.setUserId(userId);
        return user;
    }
    @Override
    public ByteBuffer serialize(User user, ProtocolVersion arg1) throws `InvalidTypeException {`
        // TODO Auto-generated method stub
        System.out.println("Executing serialize");
        ByteBuffer buffer = null;
        System.out.println("Userid to serialize: " + user.getUserId());
        try {
            buffer = ByteBuffer.wrap(user.getUserId().getBytes("UTF-8"));
            String bufferStr = new String(buffer.array(), "UTF-8");
            System.out.println("ByteBuffer to be returned: \nLength: " + `buffer.array().length +` 
                    "\nValue: " + bufferStr);
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return buffer;
    }
}

基本上,在序列化方法中,我试图提取一个 userId 字符串(使用 user.getUserId()),然后将其作为 userid 字符串存储在我的 cassandra table 中。在反序列化中,我只是将给定的 ByteBuffer 实例转换为字符串并 return 它。 这在序列化时非常适用于字符串、集合和列表(即,如果我有一个集合,编解码器对集合的每个单独元素执行 serialize() 并将相应的字符串存储在我的 casandra table 中)。但是,在反序列化 cassandra 中的集合字段期间,反序列化方法将整个集合发送到 ByteBuffer 对象中。通过分析 ByteBuffer 对象,我可以看到各个元素都在那里。请注意,反序列化是在集合的每个元素上执行的。因此,如果集合有 5 个元素,反序列化将执行 5 次,但每次都不会发送 ByteBuffer 中的特定元素,而是发送整个集合。 所以,我不明白为什么会这样,而且 google 没有太大帮助。任何 suggestions/solutions 都非常受欢迎,因为我已经坚持了很长时间了。

谢谢!

AbstractCollectionCodecSetCodecListCodec 用于 serialize/deserialize 集合的。在反序列化时,它们将位于元素开始位置 (ByteBuffer.position()) 并受单个元素结尾 (ByteBuffer.limit()) 限制的整个 ByteBuffer 传递给底层元素编解码器(在此案例,UserCodec)。

当您调用 buffer.array() 时,您将获得 ByteBuffer 的整个支持数组,而不管位置或限制。

对您来说更好的方法是使用 Bytes.getArray(ByteBuffer),其中 returns 您是 limitposition 之间数据的字节数组,即:

@Override
public User deserialize(ByteBuffer buffer, ProtocolVersion arg1) `throws InvalidTypeException {`
    // TODO Auto-generated method stub
    System.out.println("Executing deserialize");
    User user = new User();
    try {
        byte[] data = Bytes.toArray(buffer);
        System.out.println("Size of ByteBuffer: " + data.length);
        String userId = new String(data, "UTF-8");
        System.out.println("User id to set: " + userId);
        System.out.println("Setting user id...");
        user.setUserId(userId);
        System.out.println("User id set: " + user.getUserId());
    } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return user;
}

因为您只是将 User 实例作为表示其 getUserId() 的字符串存储在 C* 中,您可以做的是从 extras 模块创建 MappingCodec 的实例简单地映射 User <-> String (UserId),即:

import com.datastax.driver.core.TypeCodec;
import com.datastax.driver.extras.codecs.MappingCodec;

public class UserCodec extends MappingCodec<User, String> {

    public UserCodec() {
        super(TypeCodec.varchar(), User.class);
    }

    @Override
    protected User deserialize(String userId) {
        return new User(userId);
    }

    @Override
    protected String serialize(User user) {
        return user.getUserId();
    }
}

您可以阅读更多关于 MappingCodec on the docs site