[JAVA-4001] Automatic / package based PojoCodecs require fields Created: 05/Feb/21  Updated: 10/Mar/23

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

Type: Improvement Priority: Major - P3
Reporter: Ross Lawley Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
related to JAVA-3935 PojoCodecProvider recognition of clas... Closed
Epic Link: Investigate our POJO implementation
Quarter: FY23Q4, FY24Q2

 Description   

The following check that classModels have properties may be false.

if (automatic || (clazz.getPackage() != null && packages.contains(clazz.getPackage().getName()))) {
            try {
                classModel = createClassModel(clazz, conventions);
                if (clazz.isInterface() || !classModel.getPropertyModels().isEmpty()) {
                    discriminatorLookup.addClassModel(classModel);
                    return new AutomaticPojoCodec<T>(new PojoCodecImpl<T>(classModel, registry, propertyCodecProviders,
                            discriminatorLookup));
                }
            } catch (Exception e) {
                LOGGER.warn(format("Cannot use '%s' with the PojoCodec.", clazz.getSimpleName()), e);
                return null;
            }
        }

[1]: https://github.com/mongodb/mongo-java-driver/blob/r4.2.0/bson/src/main/org/bson/codecs/pojo/PojoCodecProvider.java#L82-L87

This causes issues when fields (properties) use a base class.

public abstract class AbstractBaseModel {
}
 
public class SettingModel extends AbstractBaseModel {
 
    @BsonId
    String id;
    SettingValueModel value;
 
    public SettingModel() {
    }
 
    public SettingModel(final String id, final SettingValueModel value) {
        this.id = id;
        this.value = value;
    }
 
    public String getId() {
        return id;
    }
 
    public SettingModel setId(final String id) {
        this.id = id;
        return this;
    }
 
    public SettingValueModel getValue() {
        return value;
    }
 
    public SettingModel setValue(final SettingValueModel value) {
        this.value = value;
        return this;
    }
 
    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        final SettingModel that = (SettingModel) o;
        return Objects.equals(id, that.id) && Objects.equals(value, that.value);
    }
 
    @Override
    public int hashCode() {
        return Objects.hash(id, value);
    }
}
@BsonDiscriminator
public class SettingValueModel extends AbstractBaseModel {
 
    public SettingValueModel() {
    }
 
}
 
@BsonDiscriminator("setting_value_sub_class_model")
public class SettingValueSubClassModel extends SettingValueModel {
 
    @BsonProperty("integer_field")
    Integer intField;
 
    public SettingValueSubClassModel() {
    }
 
    public SettingValueSubClassModel(final Integer intField) {
        this.intField = intField;
    }
 
    public Integer getIntField() {
        return intField;
    }
 
    public SettingValueSubClassModel setIntField(final Integer intField) {
        this.intField = intField;
        return this;
    }
 
    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        final SettingValueSubClassModel that = (SettingValueSubClassModel) o;
        return Objects.equals(intField, that.intField);
    }
 
    @Override
    public int hashCode() {
        return Objects.hash(intField);
    }
}
 
    @Test
    public void testAutomaticNoPropertiesField() {
        PojoCodecProvider pojoCodecProvider = PojoCodecProvider.builder().automatic(true).build();
        CodecRegistry codecRegistry = fromProviders(asList(new ValueCodecProvider(),
                new BsonValueCodecProvider(),
                pojoCodecProvider));
 
        Codec<SettingModel> codec = codecRegistry.get(SettingModel.class);
 
        SettingModel settingModel = new SettingModel("id", new SettingValueSubClassModel(1));
        RawBsonDocument rawBsonDocument = new RawBsonDocument(settingModel, codec);
        SettingModel decodedSettingsModel = rawBsonDocument.decode(codec);
 
        assertEquals(settingModel, decodedSettingsModel);
    }


Generated at Thu Feb 08 09:00:59 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.