Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Panache @BsonIgnore for methods #16399

Closed
YunaBraska opened this issue Apr 9, 2021 · 23 comments · Fixed by #18010
Closed

Panache @BsonIgnore for methods #16399

YunaBraska opened this issue Apr 9, 2021 · 23 comments · Fixed by #18010
Assignees
Labels
area/panache kind/bug Something isn't working
Milestone

Comments

@YunaBraska
Copy link

Describe the bug

Since Panache is more Domain Driven, I added also some methods with small logic which like convert a different input parameter e.g. Date to LocalDateTime or get max Date from an Array...
But for some reason @BsonIgnore only works on additional methods which are not setting fields.

Expected behaviour

I expect that the method which I mark with @BsonIgnore gets actually ignored

Actual behaviour

Example of a method which updates my lastActivity (LocalDateTime) by the max parameter of an LocalDateTime[] (Array)

//Additional Method
public User setLastActivity(final LocalDateTime... lastActivities) {
        this.lastActivity = Arrays.stream(lastActivities).max(LocalDateTime::compareTo).orElse(getTimeLastYear());
        return this;
}

//Normal Method
public User setLastActivity(LocalDateTime lastActivity) {
        this.lastActivity = lastActivity;
        return this;
}

Error on save or get:

org.bson.codecs.configuration.CodecConfigurationException: Property 'lastActivity' in User, has differing data types: TypeData{type=LocalDateTime[]} and TypeData{type=LocalDateTime}.

Error on save or get when renaming the method:

Unable to get value for property 'lastActivities' in User

A custom Codec or PojoCodec may need to be explicitly configured and registered to handle this type.

To Reproduce

  • Create a method to update manually a field on the object with different input parameter - in my example an array
  • Add @BsonIgnore to it
  • Error is happening when you try to save or get the object
@YunaBraska YunaBraska added the kind/bug Something isn't working label Apr 9, 2021
@quarkus-bot
Copy link

quarkus-bot bot commented Apr 9, 2021

/cc @FroMage, @loicmathieu

@FroMage
Copy link
Member

FroMage commented Apr 9, 2021

Mmm, perhaps we drop the annotations somehow during transformation of the setter…

@loicmathieu
Copy link
Contributor

Can you create a small reproducer project or at least provides the full stack trace ?
I wonder if the PojoCodec didn't enforce the method signature prior to checking the annotation.

@FroMage we do treat fields annotated via @BsonIgnore specifically (we exclude them from the entity model) but not methods so I don't think something will be missing in the generated class.

@YunaBraska
Copy link
Author

YunaBraska commented Apr 12, 2021

I would really like to share my project or make a sample project but I have so many issues and learnings due the new quarkus land that I am already overloaded...

My Class:

@MongoEntity(collection = "users")
public class User extends PanacheMongoEntityBase implements Comparable<User> {

    @BsonId
    @JsonProperty("id")
    @BsonProperty("_id")
    @Schema(example = "516448966")
    private Long id = -1L;

    [...]

    @JsonProperty("last_activity")
    @BsonProperty("last_activity")
    private LocalDateTime lastActivity = getTime();

    @JsonIgnore
    @BsonIgnore
    //TROUBLE METHOD CAUSES ERROR
    public User setLastActivity(final LocalDateTime... lastActivities) {
        setLastActivity(Arrays.stream(lastActivities).max(LocalDateTime::compareTo).orElse(getTimeLastYear()));
        return this;
    }

    public LocalDateTime getLastActivity() {
        return lastActivity;
    }

    public User setLastActivity(final LocalDateTime lastActivity) {
        this.lastActivity = lastActivity;
        return this;
    }

    public static List<User> dbFindById(final Iterable<?> entities) {
        if (entities.iterator().hasNext()) {
            return find("_id in ?1", entities).list();
        }
        return Collections.emptyList();
    }
}

The Error:

2021-04-12 16:47:47.616 WARN  [o.b.c.pojo] (main) Cannot use 'User' with the PojoCodec.: org.bson.codecs.configuration.CodecConfigurationException: Property 'lastActivity' in User, has differing data types: TypeData{type=LocalDateTime[]} and TypeData{type=LocalDateTime}.
	at berlin.yuna.model.db.User.dbFindById(User.java:255)
org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class berlin.yuna.model.db.User.
	at org.bson.internal.CodecCache.getOrThrow(CodecCache.java:57)
	at org.bson.internal.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:64)
	at org.bson.internal.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:39)
	at com.mongodb.internal.operation.Operations.createFindOperation(Operations.java:131)
	at com.mongodb.internal.operation.Operations.find(Operations.java:121)
	at com.mongodb.internal.operation.SyncOperations.find(SyncOperations.java:93)
	at com.mongodb.client.internal.FindIterableImpl.asReadOperation(FindIterableImpl.java:206)
	at com.mongodb.client.internal.MongoIterableImpl.execute(MongoIterableImpl.java:135)
	at com.mongodb.client.internal.MongoIterableImpl.iterator(MongoIterableImpl.java:92)
	at io.quarkus.mongodb.panache.runtime.CommonPanacheQueryImpl.list(CommonPanacheQueryImpl.java:173)
	at io.quarkus.mongodb.panache.runtime.CommonPanacheQueryImpl.list(CommonPanacheQueryImpl.java:159)
	at io.quarkus.mongodb.panache.runtime.PanacheQueryImpl.list(PanacheQueryImpl.java:116)
	at berlin.yuna.model.db.User.dbFindById(User.java:255)
	at berlin.yuna.service.UserService_ClientProxy.syncAndGet(UserService_ClientProxy.zig:455)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at io.quarkus.test.junit.QuarkusTestExtension.runExtensionMethod(QuarkusTestExtension.java:939)
	at io.quarkus.test.junit.QuarkusTestExtension.interceptTestMethod(QuarkusTestExtension.java:845)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:210)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:206)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:131)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)

@FroMage
Copy link
Member

FroMage commented Apr 14, 2021

So I confirm I can reproduce.

This works:

package io.quarkus.it.mongodb.panache.bugs;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.bson.codecs.pojo.annotations.BsonId;
import org.bson.codecs.pojo.annotations.BsonIgnore;
import org.bson.codecs.pojo.annotations.BsonProperty;

import io.quarkus.mongodb.panache.PanacheMongoEntityBase;

//@MongoEntity(collection = "Bug16399")
public class Bug16399Entity extends PanacheMongoEntityBase {
    @BsonId
    @BsonProperty("_id")
    //    @Schema(example = "516448966")
    public Long id = -1L;

    @BsonProperty("last_activity")
    public LocalDateTime lastActivity = LocalDateTime.now();

//    @BsonIgnore
//    public Bug16399Entity setLastActivity(final LocalDateTime... lastActivities) {
//        setLastActivity(Arrays.stream(lastActivities).max(LocalDateTime::compareTo).orElse(getTimeLastYear()));
//        return this;
//    }

    private LocalDateTime getTimeLastYear() {
        return null;
    }

    public LocalDateTime getLastActivity() {
        return lastActivity;
    }

    public Bug16399Entity setLastActivity(final LocalDateTime lastActivity) {
        this.lastActivity = lastActivity;
        return this;
    }

    public static List<Bug16399Entity> dbFindById(final Iterable<?> entities) {
        if (entities.iterator().hasNext()) {
            return find("_id in ?1", entities).list();
        }
        return Collections.emptyList();
    }

}

But if you comment out the method I get the same error.

I can also confirm that the method has the right annotation:

   #44 = Utf8               Lorg/bson/codecs/pojo/annotations/BsonIgnore;

  public io.quarkus.it.mongodb.panache.bugs.Bug16399Entity setLastActivity(java.time.LocalDateTime...);
    descriptor: ([Ljava/time/LocalDateTime;)Lio/quarkus/it/mongodb/panache/bugs/Bug16399Entity;
    flags: ACC_PUBLIC, ACC_VARARGS
    Code:
      stack=3, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: invokestatic  #45                 // Method java/util/Arrays.stream:([Ljava/lang/Object;)Ljava/util/stream/Stream;
         5: invokedynamic #51,  0             // InvokeDynamic #0:compare:()Ljava/util/Comparator;
        10: invokeinterface #55,  2           // InterfaceMethod java/util/stream/Stream.max:(Ljava/util/Comparator;)Ljava/util/Optional;
        15: aload_0
        16: invokevirtual #61                 // Method getTimeLastYear:()Ljava/time/LocalDateTime;
        19: invokevirtual #64                 // Method java/util/Optional.orElse:(Ljava/lang/Object;)Ljava/lang/Object;
        22: checkcast     #31                 // class java/time/LocalDateTime
        25: invokevirtual #70                 // Method setLastActivity:(Ljava/time/LocalDateTime;)Lio/quarkus/it/mongodb/panache/bugs/Bug16399Entity;
        28: pop
        29: aload_0
        30: areturn
      LineNumberTable:
        line 27: 0
        line 28: 29
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      31     0  this   Lio/quarkus/it/mongodb/panache/bugs/Bug16399Entity;
            0      31     1 lastActivities   [Ljava/time/LocalDateTime;
    RuntimeVisibleAnnotations:
      0: #44()
    MethodParameters:
      Name                           Flags
      lastActivities                 final

So at this point I'm not sure why BSON is complaining. Note that in my case I don't actually have a helpful message:

org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class io.quarkus.it.mongodb.panache.bugs.Bug16399Entity.
	at org.bson.internal.CodecCache.lambda$getOrThrow$1(CodecCache.java:52)
	at java.base/java.util.Optional.orElseThrow(Optional.java:408)
	at org.bson.internal.CodecCache.getOrThrow(CodecCache.java:51)
	at org.bson.internal.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:64)
	at org.bson.internal.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:39)
	at com.mongodb.internal.operation.Operations.getCodec(Operations.java:562)
	at com.mongodb.internal.operation.Operations.bulkWrite(Operations.java:417)
	at com.mongodb.internal.operation.Operations.insertOne(Operations.java:350)
	at com.mongodb.internal.operation.SyncOperations.insertOne(SyncOperations.java:167)
	at com.mongodb.client.internal.MongoCollectionImpl.executeInsertOne(MongoCollectionImpl.java:470)
	at com.mongodb.client.internal.MongoCollectionImpl.insertOne(MongoCollectionImpl.java:453)
	at com.mongodb.client.internal.MongoCollectionImpl.insertOne(MongoCollectionImpl.java:447)
	at io.quarkus.mongodb.panache.runtime.MongoOperations.persist(MongoOperations.java:214)
	at io.quarkus.mongodb.panache.runtime.MongoOperations.persist(MongoOperations.java:77)
	at io.quarkus.mongodb.panache.PanacheMongoEntityBase.persist(PanacheMongoEntityBase.java:36)
	at io.quarkus.it.mongodb.panache.MongodbPanacheResourceTest.testBug16399(MongodbPanacheResourceTest.java:397)
...

FroMage added a commit to FroMage/quarkus that referenced this issue Apr 14, 2021
@FroMage
Copy link
Member

FroMage commented Apr 14, 2021

Pushed a test at https://github.com/FroMage/quarkus/tree/16399, do you think you can figure out what BSON is complaining about @loicmathieu ?

@loicmathieu
Copy link
Contributor

I suspect this is a limitation of the AutomaticPojoCodec that we use that mandates that getters/setters use the same dataType.
I'll need to dig on the code as the limitation is not written inside the documentation, we should be able to reproduce this behaviour without Quarkus I think.

@loicmathieu
Copy link
Contributor

So, searching the github repo is easy ;)

This is indead a limitation of the PojoCodec, it check that the parameter class of the setter is the same than the class of the property (the field of your class): https://github.com/mongodb/mongo-java-driver/blob/5008b2a9445e477d563258eaaf4786f0f0ed83aa/bson/src/main/org/bson/codecs/pojo/PojoBuilderHelper.java#L151

So you can:

There is nothing we can do at our side, this is a limitation of the PojoCodec

@FroMage
Copy link
Member

FroMage commented Apr 14, 2021

OK, so this is not a bug then?

If not, can you add a note in our docs explaining not to do that, and what kind of exception it will cause? This way people can find it.

@loicmathieu
Copy link
Contributor

I can have a note explaing that we are using the automatic pojo codec, that rules exists, and that if a CodecConfigurationException occurs they need to check if they break one of these rules or provides a custom Codec.

I'm reluctant to specifically add this rule as it's not on the official documentation and we cannot list all the rules becasue they are written nowhere.

In fact a third solution for @YunaBraska could be to open an issue on the mongodb-java-driver repo because its method is annotated by @BsonIgnore and a correct setter exist so this may be seen as a bug inside the MongoDB driver.

Anyway, adding some section about the pojo codec seems a good addition because we rely on it for MongoDB with Panache.

@loicmathieu loicmathieu self-assigned this Apr 14, 2021
@YunaBraska
Copy link
Author

YunaBraska commented Apr 14, 2021

When I rename the method then it's complaining that the field is not defined like this:

Unable to get value for property 'lastActivities' in User

A custom Codec or PojoCodec may need to be explicitly configured and registered to handle this type.

@loicmathieu
Copy link
Contributor

@YunaBraska can you paste your updated class ?

Maybe the fact that your return the User from the setter make the PojoCodec not considering your setter as a regular setter and generate an error.

@YunaBraska
Copy link
Author

@loicmathieu its the same class as above... In that example I have the field lastActivity and want to have a custom setter with an array. As described at the start it doesn't matter how I name my additional method as I always get strange errors like Unable to get value for property. I tested it now with void instead of returning the object itself without any difference. Its somehow impossible to add additional methods which is annoying as I need now always wrapper class with back and forward translation of the object. So this nice domain driven idea of panache from my side useless as I can't enhance my methods...
Also when I am able to add @BsonIgnore to a method then I would expect that this being recognised.

Method:

    public void setLastActivities2(final LocalDateTime... lastActivities) {
        setLastActivity(Arrays.stream(lastActivities).max(LocalDateTime::compareTo).orElse(getTimeLastYear()));
    }

Error:

Unable to get value for property 'lastActivities2' in User

A custom Codec or PojoCodec may need to be explicitly configured and registered to handle this type.

	at org.bson.codecs.pojo.AutomaticPojoCodec.encode(AutomaticPojoCodec.java:53)
	at io.quarkus.mongodb.panache.runtime.MongoOperations.getBsonDocument(MongoOperations.java:279)
	at io.quarkus.mongodb.panache.runtime.MongoOperations.persistOrUpdate(MongoOperations.java:258)
	at io.quarkus.mongodb.panache.runtime.MongoOperations.persistOrUpdate(MongoOperations.java:162)
	at io.quarkus.mongodb.panache.PanacheMongoEntityBase.persistOrUpdate(PanacheMongoEntityBase.java:848)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at io.quarkus.test.junit.QuarkusTestExtension.runExtensionMethod(QuarkusTestExtension.java:939)
	at io.quarkus.test.junit.QuarkusTestExtension.interceptTestMethod(QuarkusTestExtension.java:845)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
	at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
	at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:210)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:206)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:131)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:65)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:143)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:129)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:127)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:126)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:84)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:108)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:96)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:75)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:71)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:220)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:53)
Caused by: org.bson.codecs.configuration.CodecConfigurationException: Unable to get value for property 'lastActivities2' in User
	at org.bson.codecs.pojo.PropertyAccessorImpl.getError(PropertyAccessorImpl.java:69)
	at org.bson.codecs.pojo.PropertyAccessorImpl.get(PropertyAccessorImpl.java:45)
	at org.bson.codecs.pojo.PojoCodecImpl.encodeProperty(PojoCodecImpl.java:168)
	at org.bson.codecs.pojo.PojoCodecImpl.encode(PojoCodecImpl.java:106)
	at org.bson.codecs.pojo.AutomaticPojoCodec.encode(AutomaticPojoCodec.java:50)
	... 76 more
Caused by: org.bson.codecs.configuration.CodecConfigurationException: Unable to get value for property 'lastActivities2' in User
	at org.bson.codecs.pojo.PropertyAccessorImpl.getError(PropertyAccessorImpl.java:69)
	at org.bson.codecs.pojo.PropertyAccessorImpl.get(PropertyAccessorImpl.java:42)
	... 79 more

@YunaBraska
Copy link
Author

I have finally found an ugly but simple workaround by not using words like set or get but that's not a nice convention specially as I am able to use @BsonIgnore on methods it should be recognised.

@loicmathieu
Copy link
Contributor

I suggest you raised this issue at the Mongo Java driver side.
I agree that you should be able to have arbitrary methods starting with set as long as you annotate them to be ignored

@YunaBraska
Copy link
Author

@loicmathieu which project is this. I am a bit confused who does what in quarkus.

@loicmathieu
Copy link
Contributor

This is not a Quarkus project but the official MongoDB Java Driver : https://github.com/mongodb/mongo-java-driver
The issue is a limitation of the usage of the Pojo Codec that mandates your classes to be valid Java beans (with getters and setters) or classes with public fields.

The issue is reproducible without Quarkus.

@loicmathieu
Copy link
Contributor

@YunaBraska as the issue is not on Quarkus but on the MongoDB Java Driver can we close this issue ?

@YunaBraska
Copy link
Author

@loicmathieu sorry for the late answer. I am really happy that you invested so much time and helped me in this issue :) I created a ticket on the mongo db driver but no one respond yet. I have no idea if it's possible. But I would expect and love if a framework could provide a workaround since its unclear if its getting fixed -_-

@loicmathieu
Copy link
Contributor

@YunaBraska we will not twist the way the MongoDB driver works inside Quarkus, this is not a good thing to do. MongoDB with Panache uses the AutomaticPojoCodec to serialize your object in BSON. If the AutomaticPojoCodec cannot serialize your object in BSON (in your case, this is because it's no more a classic POJO/Bean but a domain object with more methods), you must provide a custom Codec for your class.

I strongly suggest you create a MongoDB codec for your user class, it will be automatically discovered by Quarkus and registered inside the MongoDB driver codec registry, see https://quarkus.io/guides/mongodb#simplifying-mongodb-client-usage-using-bson-codec

What I will do however, will be to add more information about the AutomaticPojoCodec inside the MongoDB with Panache guide and explaining that when a CodecConfigurationException arises you should check that your object obey the PoJo codec rules and provides a Codec for the class if it is incompatible.

loicmathieu added a commit to loicmathieu/quarkus that referenced this issue Jun 18, 2021
- Update link to the latest driver version
- Improve wording
- Add a section about the PojoCodecProvider

Fixes quarkusio#16399
@loicmathieu
Copy link
Contributor

@YunaBraska I updated the guide with a section about the PojoCodecProvider and its limitation: #18010

There is nothing else we can do about your issue as it's a limitation on the PojoCodecProvider that is made for Java beans and mandates that all methods starting with set/get are getters/setters.

@YunaBraska
Copy link
Author

Okay then you can close the ticket

@loicmathieu
Copy link
Contributor

Thanks, closing it

loicmathieu added a commit to loicmathieu/quarkus that referenced this issue Jun 21, 2021
- Update link to the latest driver version
- Improve wording
- Add a section about the PojoCodecProvider

Fixes quarkusio#16399
@quarkus-bot quarkus-bot bot added this to the 2.1 - main milestone Jun 28, 2021
@gsmet gsmet modified the milestones: 2.1 - main, 2.0.1.Final Jun 28, 2021
gsmet pushed a commit to gsmet/quarkus that referenced this issue Jun 28, 2021
- Update link to the latest driver version
- Improve wording
- Add a section about the PojoCodecProvider

Fixes quarkusio#16399

(cherry picked from commit dd6a4b0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/panache kind/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants