CodecConfigurationException: Can‘t find a codec for class java.lang.Class.

前言

在使用spring data mongodb的mongoTemplate 更新数据时遇到如下错误
org.bson.codecs.configuration.CodecConfigurationException: Can’t find a codec for class java.lang.Class.

详细的错误信息

org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class java.lang.Class.

	at org.bson.internal.CodecCache.lambda$getOrThrow$1(CodecCache.java:52)
	at java.base/java.util.Optional.orElseThrow(Optional.java:403)
	at org.bson.internal.CodecCache.getOrThrow(CodecCache.java:51)
	at org.bson.internal.OverridableUuidRepresentationCodecRegistry.get(OverridableUuidRepresentationCodecRegistry.java:72)
	at org.bson.internal.ChildCodecRegistry.get(ChildCodecRegistry.java:52)
	at org.bson.codecs.DocumentCodec.writeValue(DocumentCodec.java:206)
	at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:165)
	at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:44)
	at org.bson.internal.LazyCodec.encode(LazyCodec.java:38)
	at org.bson.codecs.EncoderContext.encodeWithChildContext(EncoderContext.java:91)
	at org.bson.codecs.DocumentCodec.writeValue(DocumentCodec.java:207)
	at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:165)
	at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:44)
	at org.bson.codecs.BsonDocumentWrapperCodec.encode(BsonDocumentWrapperCodec.java:63)
	at org.bson.codecs.BsonDocumentWrapperCodec.encode(BsonDocumentWrapperCodec.java:29)
	at com.mongodb.internal.connection.SplittablePayload$WriteRequestEncoder.encode(SplittablePayload.java:221)
	at com.mongodb.internal.connection.SplittablePayload$WriteRequestEncoder.encode(SplittablePayload.java:187)
	at org.bson.codecs.BsonDocumentWrapperCodec.encode(BsonDocumentWrapperCodec.java:63)
	at org.bson.codecs.BsonDocumentWrapperCodec.encode(BsonDocumentWrapperCodec.java:29)
	at com.mongodb.internal.connection.BsonWriterHelper.writeDocument(BsonWriterHelper.java:77)
	at com.mongodb.internal.connection.BsonWriterHelper.writePayload(BsonWriterHelper.java:59)
	at com.mongodb.internal.connection.CommandMessage.encodeMessageBodyWithMetadata(CommandMessage.java:168)
	at com.mongodb.internal.connection.RequestMessage.encode(RequestMessage.java:138)
	at com.mongodb.internal.connection.CommandMessage.encode(CommandMessage.java:62)
	at com.mongodb.internal.connection.InternalStreamConnection.sendAndReceive(InternalStreamConnection.java:326)
	at com.mongodb.internal.connection.UsageTrackingInternalConnection.sendAndReceive(UsageTrackingInternalConnection.java:116)
	at com.mongodb.internal.connection.DefaultConnectionPool$PooledConnection.sendAndReceive(DefaultConnectionPool.java:647)
	at com.mongodb.internal.connection.CommandProtocolImpl.execute(CommandProtocolImpl.java:71)
	at com.mongodb.internal.connection.DefaultServer$DefaultServerProtocolExecutor.execute(DefaultServer.java:244)
	at com.mongodb.internal.connection.DefaultServerConnection.executeProtocol(DefaultServerConnection.java:227)
	at com.mongodb.internal.connection.DefaultServerConnection.command(DefaultServerConnection.java:127)
	at com.mongodb.internal.connection.DefaultServer$OperationCountTrackingConnection.command(DefaultServer.java:357)
	at com.mongodb.internal.operation.MixedBulkWriteOperation.executeCommand(MixedBulkWriteOperation.java:477)
	at com.mongodb.internal.operation.MixedBulkWriteOperation.executeBulkWriteBatch(MixedBulkWriteOperation.java:339)
	at com.mongodb.internal.operation.MixedBulkWriteOperation.lambda$execute$2(MixedBulkWriteOperation.java:260)
	at com.mongodb.internal.operation.OperationHelper.lambda$withSourceAndConnection$2(OperationHelper.java:564)
	at com.mongodb.internal.operation.OperationHelper.withSuppliedResource(OperationHelper.java:589)
	at com.mongodb.internal.operation.OperationHelper.lambda$withSourceAndConnection$3(OperationHelper.java:563)
	at com.mongodb.internal.operation.OperationHelper.withSuppliedResource(OperationHelper.java:589)
	at com.mongodb.internal.operation.OperationHelper.withSourceAndConnection(OperationHelper.java:562)
	at com.mongodb.internal.operation.MixedBulkWriteOperation.lambda$execute$3(MixedBulkWriteOperation.java:232)
	at com.mongodb.internal.async.function.RetryingSyncSupplier.get(RetryingSyncSupplier.java:65)
	at com.mongodb.internal.operation.MixedBulkWriteOperation.execute(MixedBulkWriteOperation.java:268)
	at com.mongodb.internal.operation.MixedBulkWriteOperation.execute(MixedBulkWriteOperation.java:84)
	at com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor.execute(MongoClientDelegate.java:212)
	at com.mongodb.client.internal.MongoCollectionImpl.executeSingleWriteRequest(MongoCollectionImpl.java:1010)
	at com.mongodb.client.internal.MongoCollectionImpl.executeUpdate(MongoCollectionImpl.java:994)
	at com.mongodb.client.internal.MongoCollectionImpl.updateOne(MongoCollectionImpl.java:579)
	at org.springframework.data.mongodb.core.MongoTemplate.lambda$doUpdate$20(MongoTemplate.java:1695)
	at org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:560)
	at org.springframework.data.mongodb.core.MongoTemplate.doUpdate(MongoTemplate.java:1668)
	at org.springframework.data.mongodb.core.MongoTemplate.updateFirst(MongoTemplate.java:1599)
	at com.wn.cloud.recommend.gateway.repository.mongo.impl.MongoRepositoryImpl.updateFirst(MongoRepositoryImpl.java:243)
	at com.wn.cloud.recommend.gateway.repository.mongo.impl.MongoRepositoryImpl$$FastClassBySpringCGLIB$$e32636f.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
	at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708)
	at com.wn.cloud.recommend.gateway.repository.mongo.impl.MongoRepositoryImpl$$EnhancerBySpringCGLIB$$ac6a30e3.updateFirst(<generated>)
	at com.wn.cloud.recommend.gateway.impl.MongoGatewayImpl.updateFirst(MongoGatewayImpl.java:270)
	at com.wn.cloud.recommend.service.test.ProcessTest.test(ProcessTest.java:57)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
	at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
	at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)

问题现场


@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)
public class ProcessTest {

    @Autowired
    private MongoGateway mongoGateway;

    @Test
    public void test() {
        String collectionName = mongoGateway.getCollectionName(User.class);
        System.out.println(collectionName);

        User user = new User();
        user.setId(1L);
        user.setUser_id(1111L);
        user.setAge(10);
        User user1 = mongoGateway.save(user, "user");
        System.out.println("新增user: " + JSON.toJSONString(user1));

        Query query = new Query();
        Criteria criteria = new Criteria(TableInfoEnum.USER.getUniqueFieldName());
        criteria.is(user.getUser_id());
        query.addCriteria(criteria);

        user.setAge(18);
        Update update = new Update();
        setUpdate(update, user);
        mongoGateway.updateFirst(query, update, User.class, "user");

        User one = mongoGateway.findOne(query, User.class, "user");
        System.out.println("one: " + JSON.toJSONString(one));
    }

    public void setUpdate(Update update, Object object) {
        if (null == object) {
            return;
        }
        Class<?> clazz = object.getClass();

        BeanInfo beanInfo;
        try {
            beanInfo = Introspector.getBeanInfo(clazz);

            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
                String name = propertyDescriptor.getName();
                    Method readMethod = propertyDescriptor.getReadMethod();
                    readMethod.setAccessible(true);
                    Object invoke = readMethod.invoke(object, null);
                    if (null != invoke) {
                        update.set(name, invoke);
                        // 后来新增
                        System.out.println("name: " + name + " invoke: " + invoke);
                    }

            }
        } catch (IntrospectionException | InvocationTargetException | IllegalAccessException e) {
            log.error("setUpdate属性失败,错误日志: {[]}", e);
        }


    }
}

代码的功能也很简单
第一个插入数据 使用到了 save
第二个 更新数据 使用到了 updateFirst

在updateFirst 更新方法中 会调用 setUpdate 进行属性复制 会把 User对象的属性 以及属性值都设置给Update 然后 进行更新

分析

刚开始以为缺少了什么 CodeC的加解密类 后来又增加了 日志打印设置的属性以及属性值 System.out.println("name: " + name + " invoke: " + invoke); 后来发现属性中居然有个class的 属性名 后来一想也是正常的 因为java的类默认有个Object父类然后在这个父类中 有个class属性以及 获取class的方法

public class Object {

    private static native void registerNatives();
    static {
        registerNatives();
    }


    public final native Class<?> getClass();
}    

然后在 mongoTemplate 的配置并未设置class的属性的编解码器 所以就报错了

解决

方式一: 设置解析class属性的 Codec 编解码器

import org.bson.BsonReader;
import org.bson.BsonWriter;
import org.bson.codecs.Codec;
import org.bson.codecs.DecoderContext;
import org.bson.codecs.EncoderContext;

public class ClassCodec implements Codec<Class<?>> {

    @Override
    public void encode(BsonWriter writer, Class<?> value, EncoderContext encoderContext) {
        // 在此处实现将 Class 对象编码为 BSON 的逻辑
        // 例如,您可以将类名编码为字符串并写入 BsonWriter
        writer.writeString(value.getName());
    }

    @Override
    public Class<?> decode(BsonReader reader, DecoderContext decoderContext) {
        // 在此处实现将 BSON 解码为 Class 对象的逻辑
        // 例如,您可以从 BsonReader 读取字符串并使用 Class.forName() 加载相应的类
        String className = reader.readString();
        try {
            return Class.forName(className);
        } catch (ClassNotFoundException e) {
            throw new IllegalArgumentException("Failed to decode Class object.", e);
        }
    }

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

然后注册这个class编解码器 到mongodb template 即可 这是是将class的属性转化为className的字符串存储 然后读取也是读取这个字符串 如果需要 可以自行扩展实现

方式二: 排除掉这个属性的设置即可

public void setUpdate(Update update, Object object) {
    if (null == object) {
        return;
    }
    Class<?> clazz = object.getClass();

    BeanInfo beanInfo;
    try {
        beanInfo = Introspector.getBeanInfo(clazz);

        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
            String name = propertyDescriptor.getName();
            if (!"class".equalsIgnoreCase(name)) {
                Method readMethod = propertyDescriptor.getReadMethod();
                readMethod.setAccessible(true);
                Object invoke = readMethod.invoke(object, null);
                if (null != invoke) {
                    update.set(name, invoke);
                    System.out.println("name: " + name + " invoke: " + invoke);
                }
            }

        }
    } catch (IntrospectionException | InvocationTargetException | IllegalAccessException e) {
        log.error("setUpdate属性失败,错误日志: {[]}", e);
    }
}

the end !!!
good day ! !!

  • 20
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值