Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

Here is the piece of code I have

MyValue sampleValue = Values.newHeapInstance(MyValue.class); 
// subsequently set the couple of floats and int i have defined in MyValue interface
ChronicleMap<MyKey, MyValue> cache = ChronicleMapBuilder.of(MyKey.class, MyValue.class)
                .entries(100)
                .averageValue(sampleValue)
                .create();

When I do this I get the error

java.lang.IllegalArgumentException: Using BytesMarshallable and an interface value type not supported at net.openhft.chronicle.map.ChronicleMapBuilder.averageValue(ChronicleMapBuilder.java:660)

Can someone help me understand if this usage pattern is in-correct?

If I change to creating MyValue by implementing a concrete class and then doing a new on that as follows it works:

MyValue sampleValue = new MyValueImpl();
// subsequently set the couple of floats and int i have defined in MyValue interface
ChronicleMap<MyKey, MyValue> cache = ChronicleMapBuilder.of(MyKey.class, MyValue.class)
                .entries(100)
                .averageValue(sampleValue)
                .create();

The reason for this exception can be found in the source:

            if (Serializable.class.isAssignableFrom(valueClass))
                LOG.warn("BytesMarshallable " + valueClass + " will be serialized as Serializable as the value class is an interface");
                throw new IllegalArgumentException("Using BytesMarshallable and an interface value type not supported");

Which simply calls the isAssignableFrom method of the class Class which checks:

Determines if the class or interface represented by this Class object is either the same as, or is a superclass or superinterface of, the class or interface represented by the specified Class parameter. It returns true if so; otherwise it returns false. If this Class object represents a primitive type, this method returns true if the specified Class parameter is exactly this Class object; otherwise it returns false.

So this checks if the Serializable Class is represented by the valueClass. So my understanding is that your MyValue isn't implementing the Serializable interface.

And yeah, even the comment states it:

Configures the average number of bytes, taken by serialized form of values

So If I'm not mistaken, simply let your Value Class implement the Serializable interface and you should be fine. Pretty ... confusing exception message I'd say.

Use of Values.newHeapInstance() suggests that MyValue is a so-called value interface. Objects of a specific value interface have constant size in serialized form. Value interfaces are supported by ChronicleMap specially, so you shouldn't configure value size at all, as presented in this example from tutorial:

ChronicleMap<LongValue, Order> orders = ChronicleMap
    .of(LongValue.class, Order.class)
    .name("orders-map")
    .entries(1_000_000)
    .create();
LongValue key = Values.newHeapInstance(LongValue.class);
key.setValue(id);
orders.put(key, order);

Note that there is no averageValue() call, nor averageValueSize(), nor constantValueSizeBySample().

The presented error message is indeed confusing, especially since ChronicleMap already knows that value class is a value interface and knows it's size. Feel free to open an issue in https://github.com/OpenHFT/Chronicle-Map.

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.