[JAVA-2920] Add support for Map<String, List<Object>> and Map<String, List<AnotherPojo>> in PojoCodec Created: 29/Jul/18  Updated: 26/Nov/19  Resolved: 10/Aug/18

Status: Closed
Project: Java Driver
Component/s: POJO
Affects Version/s: 3.8.0
Fix Version/s: None

Type: Task Priority: Minor - P4
Reporter: Durga Deep Assignee: Unassigned
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

mac os



 Description   

We're getting an Exception in the following function.

We have a Pojo that has two members 

private Map<String, List<MyPojo>> ref;
private Map<String, List<Object>> myInnerParam;

Debugging shows that the following function throws an Exception (CodecConfigurationException)
 
private void specialize() {
 if (specialized) {
 codecCache.put(classModel, this);
 for (PropertyModel<?> propertyModel : classModel.getPropertyModels()) {
 try {
 addToCache(propertyModel);
 } catch (Exception e) {
 throw new CodecConfigurationException(format("Could not create a PojoCodec for '%s'."
 + " Property '%s' errored with: %s", classModel.getName(), propertyModel.getName(), e.getMessage()), e);
 }
 }
 }
}

 

The Value of the PropertyModel in the above function.

propertyModel = {PropertyModel@10278} "PropertyModel{propertyName='myInnerParam', readName='myInnerParam', writeName='myInnerParam', typeData=TypeData{type=Map, typeParameters=[String, List<Object>]}}"

name = "myInnerParam"

readName = "myInnerParam"

writeName = "myInnerParam"

typeData = {TypeData@10350} "TypeData{type=Map, typeParameters=[String, List<Object>]}"

codec = null

propertySerialization = {PropertyModelSerializationImpl@10351}

useDiscriminator = null

propertyAccessor = {PropertyAccessorImpl@10352}

cachedCodec = null

 

 

Exception

e = {CodecConfigurationException@11668} "org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class java.lang.Object."
 detailMessage = "Can't find a codec for class java.lang.Object."
 value = {char[46]@11905} 
 hash = 0
 cause = {CodecConfigurationException@11668} "org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class java.lang.Object."
 detailMessage = "Can't find a codec for class java.lang.Object."
 cause = {CodecConfigurationException@11668} "org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class java.lang.Object."
 stackTrace = {StackTraceElement[0]@11901} 
 suppressedExceptions = {Collections$UnmodifiableRandomAccessList@11902} size = 0
 stackTrace = {StackTraceElement[0]@11901} 
 suppressedExceptions = {Collections$UnmodifiableRandomAccessList@11902} size = 0

 This is a stopper for us - and we are not able to move forward to using the latest Driver - also can you please suggest a work around - if this is something that will take a long time.

 



 Comments   
Comment by sam s [ 26/Nov/19 ]

Thanks

Comment by Ross Lawley [ 26/Nov/19 ]

Hi ananthas@nedbank.co.za,

Please don't comment on closed tickets as we are likely to miss the comment. As mentioned above the best place for questions regarding MongoDB usage or the Java driver specifics is the mongodb-user mailinglist or stackoverflow as you will reach a boarder audience there. If your business requires an answer from MongoDB within a time frame then we do offer production support.

For driver version and MongoDB version please see the driver compatibility chart.

Kind Regards,

Ross

Comment by Durga Deep [ 10/Aug/18 ]

Thanks a lot for your help Ross.. I will post a link.

Comment by Ross Lawley [ 10/Aug/18 ]

I've added JAVA-2923 to see if Map<String, List<Object>> can be handled by the generic MapCodec.

Comment by Ross Lawley [ 10/Aug/18 ]

Hi durgadeep,

Looks like there isn't a fooData.getBarCode() method in the code provided. Also BarCode has no public properties, which may be the cause? Without more information I can't debug the issue. Can you get a codec from the registry for each of the sub classes? eg: codecRegistry.get(AP.class);

As the original question has been addressed, I'm going to close this ticket. The best place for questions regarding MongoDB usage or the Java driver specifics is the mongodb-user mailinglist or stackoverflow as you will reach a boarder audience there. If your business requires an answer from MongoDB within a time frame then we do offer production support.

If you do follow up via one of the options above please post a link and I will follow the conversation there.

Thanks

Ross

Comment by Durga Deep [ 09/Aug/18 ]

Hi Ross,

 Sorry for the delay, here are the POJOs

 

public class Foo extends Summary {
public Foo() {}
 private BarCode barCode;
}
------------------------------------------------
public class BarCode {
   public BarCode() {
   }
    private AP ap;
}
------------------------------------------------
public class AP implements RA {
    private String desc;
    public AP(String desc) {
        this.desc = desc;
    }
    @Override
    public void accept(final Foo fooData, final Map<String, Object> transientKV) {
        fooData.getBarCode().setAP(this);
    }
------------------------------------------------
@FunctionalInterface
public interface RA {
    void accept(Foo FooData, final Map<String, Object> keyTrans);
}

The Exception

 

org.bson.codecs.configuration.CodecConfigurationException: Could not create a PojoCodec for 'Foo'. Property 'barCode' errored with: Can't find a codec for class com.foobar.service.data.BarCode.
 at org.bson.codecs.pojo.PojoCodecImpl.specialize(PojoCodecImpl.java:82) ~[bson-3.7.1.jar:?]
 at org.bson.codecs.pojo.PojoCodecImpl.<init>(PojoCodecImpl.java:60) ~[bson-3.7.1.jar:?]
 at org.bson.codecs.pojo.PojoCodecProvider.getPojoCodec(PojoCodecProvider.java:86) ~[bson-3.7.1.jar:?]
 at org.bson.codecs.pojo.PojoCodecProvider.get(PojoCodecProvider.java:68) ~[bson-3.7.1.jar:?]
 at org.bson.codecs.configuration.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:43) ~[bson-3.7.1.jar:?]
 at org.bson.codecs.configuration.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:55) ~[bson-3.7.1.jar:?]
 at org.bson.codecs.configuration.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:37) ~[bson-3.7.1.jar:?]
 at com.mongodb.internal.operation.Operations.getCodec(Operations.java:487) ~[mongodb-driver-core-3.7.0.jar:?]

 

Thanks a lot...

 

Comment by Ross Lawley [ 08/Aug/18 ]

Hi durgadeep,

Please could you provide the whole POJO and the error message? As the example only has a single private field.

Ross

Comment by Durga Deep [ 07/Aug/18 ]

Hi Ross,

   Yes it does have a public constructor - still no luck

 

Comment by Ross Lawley [ 07/Aug/18 ]

durgadeep,

Have you got a public constructor for that class or an annotated static creator method? If not you'll need to add one.

Ross

Comment by Durga Deep [ 06/Aug/18 ]

Hi Ross,

  Here is another scenario - need advice.

The following scenario is throwing a similar Exception as documented earlier.

PropertyModel{propertyName='ap', readName='ap', writeName='ap', typeData=TypeData{type=AP}}

 

public class AP implements RA {
 
 private String testing;
 
 @Override
 public void visit(final ABC data, final Map<String, Object> keyMap) {
}
}

 

 

How should I define the convention for this parameter (function Parameter) - is there something I need to do ?

 

Thank you

 

 

Comment by Durga Deep [ 31/Jul/18 ]

Hi Ross,

   Thanks a million - that helped. 95% of the code is functional, with the exception of another use case. I will update this ticket with the specifics

Thanks again

_Durga Deep

Comment by Ross Lawley [ 30/Jul/18 ]

Hi durgadeep,

Thanks for the ticket. By default the PojoCodec does not support unspecialized types (eg: Object) for Fields, Map value types or Lists value types. When looking up the codec to use for the myInnerParam field it is failing to find a Codec for Object.class and that is causing the error.

The work around would be either to define a Codec to handle Object.class and add it to the registry. Alternatively, you could a convention to set the field to encode / decode using the MapCodec like so:

        List<Convention> conventions = new ArrayList<Convention>(DEFAULT_CONVENTIONS);
        conventions.add(new Convention() {
            @Override
            public void apply(final ClassModelBuilder<?> classModelBuilder) {
                if (classModelBuilder.getType().equals(NestedMapStringObjectModel.class)) {
                    ((PropertyModelBuilder<Map<String, Object>>) classModelBuilder.getProperty("myInnerParam")).codec(new MapCodec());
                }
            }
        });

I hope that helps,

Ross

Generated at Thu Feb 08 08:58:22 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.