无法找到 java.lang.Object 类的编解码器。

huangapple go评论110阅读模式
英文:

Can't find a codec for class java.lang.Object

问题

我创建了一个简单的实体,其中包含一个类型为Object的属性,因为我无法控制其类型,它可以是String或一个对象。

@MongoEntity(collection = "myCollection", clientName = "mongoClient1")
public class MyClass extends EntityId {
private String name;
private Int age;
private Object payload;

//Getters and Setters
...
}


我尝试插入数据,但出现了以下错误:

> 由于找不到java.lang.Object类的编解码器,导致的org.bson.codecs.configuration.CodecConfigurationException。

我尝试将属性更改为Document、BsonDocument和BsonValue,但当其值为String类型时,会出现另一种异常,因为无法对这些类型进行字符串反序列化。

有人有解决这个问题的想法吗?
英文:

I created a simple entity with a property of type Object, because I can't control its type, it can be String or an object.

@MongoEntity(collection = "myCollection", clientName = "mongoClient1")
public class MyClass extends EntityId {
   private String name;
   private Int age;
   private Object payload;

   //Getters and Setters
   ...
}

I am trying to insert but the following error is occurring:

> Caused by: org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class java.lang.Object

I tried to change the property to Document, BsonDocument and BsonValue but when its value is of type String another exception occurs because it is not possible to deserialize string for these types.

Does anyone have an idea how to solve this problem?

答案1

得分: 1

通过 @DiegoBorda 的提示以及进行了广泛的研究和与 ChatGPT 的讨论,我提出了一个解决方案,这个解决方案对我有效。

我分享这个解决方案是因为其他人可能会遇到相同的问题。

我创建了一个ObjectCodec,它是作为Codec实现的。

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.bson.BsonReader;
import org.bson.BsonType;
import org.bson.BsonWriter;
import org.bson.codecs.Codec;
import org.bson.codecs.DecoderContext;
import org.bson.codecs.EncoderContext;
import org.bson.types.Decimal128;

public class ObjectCodec implements Codec<Object> {

    @Override
    public void encode(BsonWriter writer, Object value, EncoderContext encoderContext) {
        writeValue(writer, value);
    }

    @Override
    public Class<Object> getEncoderClass() {
        return Object.class;
    }

    @Override
    public Object decode(BsonReader reader, DecoderContext decoderContext) {
        return readValue(reader);
    }

    private static Object readValue(BsonReader bsonReader) {
        var type = bsonReader.getCurrentBsonType();
        switch (type) {
            case ARRAY:
                ArrayList<Object> array = new ArrayList<>();
                bsonReader.readStartArray();
                while (bsonReader.readBsonType() != BsonType.END_OF_DOCUMENT) {
                    array.add(readValue(bsonReader));
                }
                bsonReader.readEndArray();
                return array;
            case BINARY:
                return bsonReader.readBinaryData();
            case BOOLEAN:
                return bsonReader.readBoolean();
            case DATE_TIME:
                return bsonReader.readDateTime();
            case DB_POINTER:
                return bsonReader.readDBPointer();
            case DECIMAL128:
                return bsonReader.readDecimal128();
            case DOCUMENT:
                HashMap<String, Object> nestedMap = new HashMap<>();
                bsonReader.readStartDocument();
                while (bsonReader.readBsonType() != BsonType.END_OF_DOCUMENT) {
                    nestedMap.put(bsonReader.readName(), readValue(bsonReader));
                }
                bsonReader.readEndDocument();
                return nestedMap;
            case DOUBLE:
                return bsonReader.readDouble();
            case INT32:
                return bsonReader.readInt32();
            case INT64:
                return bsonReader.readInt64();
            case NULL:
                return null;
            case OBJECT_ID:
                return bsonReader.readObjectId();
            case STRING:
                return bsonReader.readString();
            case TIMESTAMP:
                return bsonReader.readTimestamp();
            case UNDEFINED:
                return null;
            default:
                return null;

        }
    }

    private static void writeValue(BsonWriter bsonWriter, Object value) {
        if (value instanceof String) {
            bsonWriter.writeString(value.toString());
        } else if (value instanceof Integer) {
            bsonWriter.writeInt32((Integer) value);
        } else if (value instanceof Long) {
            bsonWriter.writeInt64((Long) value);
        } else if (value instanceof BigDecimal) {
            bsonWriter.writeDecimal128(Decimal128.parse(value.toString()));
        } else if (value instanceof Double) {
            bsonWriter.writeDouble((Double) value);
        } else if (value instanceof Boolean) {
            bsonWriter.writeBoolean((Boolean) value);
        } else if (value instanceof HashMap) {
            // 递归处理 HashMap 进行嵌套
            bsonWriter.writeStartDocument();
            HashMap<?, ?> nestedMap = (HashMap<?, ?>) value;
            for (Map.Entry<?, ?> entry : nestedMap.entrySet()) {
                String key = entry.getKey().toString();
                Object nestedValue = entry.getValue();
                bsonWriter.writeName(key);
                writeValue(bsonWriter, nestedValue);
            }
            bsonWriter.writeEndDocument();
        } else if (value instanceof ArrayList) {
            ArrayList<?> arrayList = (ArrayList<?>) value;
            bsonWriter.writeStartArray();
            for (Object item : arrayList) {
                writeValue(bsonWriter, item);
            }
            bsonWriter.writeEndArray();
        } else if (value.getClass().isArray()) {
            bsonWriter.writeStartArray();
            int length = java.lang.reflect.Array.getLength(value);
            for (int i = 0; i < length; i++) {
                Object item = java.lang.reflect.Array.get(value, i);
                writeValue(bsonWriter, item);
            }
            bsonWriter.writeEndArray();
        } else {
            try {
                Class<?> clazz = value.getClass();
                bsonWriter.writeStartDocument();
                while (clazz != null) {
                    Field[] fields = clazz.getDeclaredFields();
                    for (Field field : fields) {
                        int modifiers = field.getModifiers();
                        if (!java.lang.reflect.Modifier.isFinal(modifiers)) {
                            field.setAccessible(true);
                            String fieldName = field.getName();
                            if (fieldName.equals("id")) {
                                fieldName = "_id";
                            }
                            Object fieldValue = field.get(value);
                            bsonWriter.writeName(fieldName);
                            writeValue(bsonWriter, fieldValue);
                        }
                    }
                    clazz = clazz.getSuperclass();
                }
                bsonWriter.writeEndDocument();

            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
}

然后,通过实例化ObjectCodec来创建一个自定义编解码器提供程序。

import io.quarkus.runtime.annotations.RegisterForReflection;
import org.bson.codecs.Codec;
import org.bson.codecs.configuration.CodecProvider;
import org.bson.codecs.configuration.CodecRegistry;

import javax.inject.Singleton;

@Singleton
@RegisterForReflection
public class CustomCodecProvider implements CodecProvider {
    private final Codec<Object> objectCodec;

    public CustomCodecProvider() {
        // 创建自定义 ObjectCodec 的实例,并在需要时传递默认的 CodecRegistry 供内部使用。
        this.objectCodec = new ObjectCodec();
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T> Codec<T> get(Class<T> clazz, CodecRegistry registry) {
        // 检查类型是否为 Object,然后返回自定义 ObjectCodec。
        if (clazz == Object.class) {
            return (Codec<T>) objectCodec;
        }
        return null; // 如果类型不是 Object,则返回 null,以便使用其他默认的 MongoDB 编解码器。
    }
}

然后,我需要在application.properties中注册CustomCodecProvider

quarkus:
mongodb:
codec-providers: br.com.api.infra.crosscutting.ioc.config.CustomCodecProvider

这对我有效,但如果有其他解决方案,我愿意尝试它们。

英文:

With @DiegoBorda's tip and after doing extensive research and discussion with ChatGPT I came up with a solution that worked for me.

I am sharing this solution because other people might encounter the same issue.

I created an ObjectCodec implemented as a Codec.

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.bson.BsonReader;
import org.bson.BsonType;
import org.bson.BsonWriter;
import org.bson.codecs.Codec;
import org.bson.codecs.DecoderContext;
import org.bson.codecs.EncoderContext;
import org.bson.types.Decimal128;

public class ObjectCodec implements Codec&lt;Object&gt; {

    @Override
    public void encode(BsonWriter writer, Object value, EncoderContext encoderContext) {
        writeValue(writer, value);
    }

    @Override
    public Class&lt;Object&gt; getEncoderClass() {
        return Object.class;
    }

    @Override
    public Object decode(BsonReader reader, DecoderContext decoderContext) {
        return readValue(reader);
    }

    private static Object readValue(BsonReader bsonReader) {
        var type = bsonReader.getCurrentBsonType();
        switch (type) {
            case ARRAY:
                ArrayList&lt;Object&gt; array = new ArrayList&lt;&gt;();
                bsonReader.readStartArray();
                while (bsonReader.readBsonType() != BsonType.END_OF_DOCUMENT) {
                    array.add(readValue(bsonReader));
                }
                bsonReader.readEndArray();
                return array;
            case BINARY:
                return bsonReader.readBinaryData();
            case BOOLEAN:
                return bsonReader.readBoolean();
            case DATE_TIME:
                return bsonReader.readDateTime();
            case DB_POINTER:
                return bsonReader.readDBPointer();
            case DECIMAL128:
                return bsonReader.readDecimal128();
            case DOCUMENT:
                HashMap&lt;String, Object&gt; nestedMap = new HashMap&lt;&gt;();
                bsonReader.readStartDocument();
                while (bsonReader.readBsonType() != BsonType.END_OF_DOCUMENT) {
                    nestedMap.put(bsonReader.readName(), readValue(bsonReader));
                }
                bsonReader.readEndDocument();
                return nestedMap;
            case DOUBLE:
                return bsonReader.readDouble();
            case INT32:
                return bsonReader.readInt32();
            case INT64:
                return bsonReader.readInt64();
            case NULL:
                return null;
            case OBJECT_ID:
                return bsonReader.readObjectId();
            case STRING:
                return bsonReader.readString();
            case TIMESTAMP:
                return bsonReader.readTimestamp();
            case UNDEFINED:
                return null;
            default:
                return null;

        }
    }

    private static void writeValue(BsonWriter bsonWriter, Object value) {
        if (value instanceof String) {
            bsonWriter.writeString(value.toString());
        } else if (value instanceof Integer) {
            bsonWriter.writeInt32((Integer) value);
        } else if (value instanceof Long) {
            bsonWriter.writeInt64((Long) value);
        } else if (value instanceof BigDecimal) {
            bsonWriter.writeDecimal128(Decimal128.parse(value.toString()));
        } else if (value instanceof Double) {
            bsonWriter.writeDouble((Double) value);
        } else if (value instanceof Boolean) {
            bsonWriter.writeBoolean((Boolean) value);
        } else if (value instanceof HashMap) {
            // Recursively handle HashMap for nesting
            bsonWriter.writeStartDocument();
            HashMap&lt;?, ?&gt; nestedMap = (HashMap&lt;?, ?&gt;) value;
            for (Map.Entry&lt;?, ?&gt; entry : nestedMap.entrySet()) {
                String key = entry.getKey().toString();
                Object nestedValue = entry.getValue();
                bsonWriter.writeName(key);
                writeValue(bsonWriter, nestedValue);
            }
            bsonWriter.writeEndDocument();
        } else if (value instanceof ArrayList) {
            ArrayList&lt;?&gt; arrayList = (ArrayList&lt;?&gt;) value;
            bsonWriter.writeStartArray();
            for (Object item : arrayList) {
                writeValue(bsonWriter, item);
            }
            bsonWriter.writeEndArray();
        } else if (value.getClass().isArray()) {
            bsonWriter.writeStartArray();
            int length = java.lang.reflect.Array.getLength(value);
            for (int i = 0; i &lt; length; i++) {
                Object item = java.lang.reflect.Array.get(value, i);
                writeValue(bsonWriter, item);
            }
            bsonWriter.writeEndArray();
        } else {
            try {
                Class&lt;?&gt; clazz = value.getClass();
                bsonWriter.writeStartDocument();
                while (clazz != null) {
                    Field[] fields = clazz.getDeclaredFields();
                    for (Field field : fields) {
                        int modifiers = field.getModifiers();
                        if (!java.lang.reflect.Modifier.isFinal(modifiers)) {
                            field.setAccessible(true);
                            String fieldName = field.getName();
                            if (fieldName.equals(&quot;id&quot;)) {
                                fieldName = &quot;_id&quot;;
                            }
                            Object fieldValue = field.get(value);
                            bsonWriter.writeName(fieldName);
                            writeValue(bsonWriter, fieldValue);
                        }
                    }
                    clazz = clazz.getSuperclass();
                }
                bsonWriter.writeEndDocument();

            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
}

Then create a Custom Codec Provider by instantiating my ObjectCodec.

import io.quarkus.runtime.annotations.RegisterForReflection;
import org.bson.codecs.Codec;
import org.bson.codecs.configuration.CodecProvider;
import org.bson.codecs.configuration.CodecRegistry;

import javax.inject.Singleton;

@Singleton
@RegisterForReflection
public class CustomCodecProvider implements CodecProvider {
    private final Codec&lt;Object&gt; objectCodec;

    public CustomCodecProvider() {
        // Create an instance of the custom ObjectCodec and pass the default CodecRegistry for internal use, if needed.
        this.objectCodec = new ObjectCodec();
    }

    @Override
    @SuppressWarnings(&quot;unchecked&quot;)
    public &lt;T&gt; Codec&lt;T&gt; get(Class&lt;T&gt; clazz, CodecRegistry registry) {
        // Check if the type is Object and return the custom ObjectCodec.
        if (clazz == Object.class) {
            return (Codec&lt;T&gt;) objectCodec;
        }
        return null; // If the type is not Object, return null to let other default MongoDB codecs be used.
    }
}

Then I had to register the CustomCodecProvider in my application.properties.

quarkus:
mongodb:
codec-providers: br.com.api.infra.crosscutting.ioc.config.CustomCodecProvider

This is working for me, but if anyone has other solutions, I'd like to try them out.

huangapple
  • 本文由 发表于 2023年7月28日 02:41:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/76782606.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定