Skip to content

ClassCastException: MissingProperty cannot be cast to java.lang.Double #935

@mdii

Description

@mdii

Hello, we have a use case that needs a custom comparator for Double values. However in some cases we get the following exception:

java.lang.ClassCastException: org.javers.core.metamodel.property.MissingProperty cannot be cast to java.lang.Double
	at org.javers.core.metamodel.type.CustomValueComparatorNullSafe.equals(CustomValueComparatorNullSafe.java:29)
	at org.javers.core.metamodel.type.PrimitiveOrValueType.equals(PrimitiveOrValueType.java:32)
	at org.javers.core.diff.appenders.ValueChangeAppender.calculateChanges(ValueChangeAppender.java:34)
	at org.javers.core.diff.appenders.ValueChangeAppender.calculateChanges(ValueChangeAppender.java:10)
	at org.javers.core.diff.DiffFactory.appendChanges(DiffFactory.java:153)
	at org.javers.core.diff.DiffFactory.appendPropertyChanges(DiffFactory.java:143)
....

I managed to reproduce it in the following test case.

class CustomValueComparatorCase extends Specification {
    class Parent {}

    class Child1 extends Parent {
        String prop1
    }

    class Child2 extends Parent {
        Double prop2
    }

    class Container {
        Map<String, Parent> map = new HashMap<>()
    }

    class CustomDoubleComparator implements CustomValueComparator<Double> {
        @Override
        boolean equals(Double a, Double b) {
            return round(a) == round(b)
        }

        @Override
        String toString(Double value) {
            return round(value).toString()
        }

        private BigDecimal round(Double val) {
            return NumberUtils.toScaledBigDecimal(val, 4, RoundingMode.HALF_UP)
        }
    }

    def "should compare map values using their concrete type"() {
        given:
        def javers = JaversBuilder.javers()
                .registerValue(Double.class, new CustomDoubleComparator())
                .build()

        when:
        Parent c1 = new Child1(prop1: "Hi")
        Parent c2 = new Child2(prop2: 1.2)


        Container container1 = new Container()
        container1.map.put("key", c1)

        Container container2 = new Container()
        container2.map.put("key", c2)

        def diff = javers.compare(container1, container2)

        then:
        diff.changes.size() > 0

        println(diff.changes)
    }
}

It seems that Javers sees the values in the map as Parent type not the concrete type.
If I change Map<String, Parent> map to Map<String, Object> map then the test passes.
If I keep Map<String, Parent> map and compare the maps directly like javers.compare(container1.map, container2.map) then the test passes.

Would it be possible to avoid this exception?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions