Search code examples
javaignitegridgaindistributed-caching

Ignite marshalling of Java Record Typed keys


I was trying to use a Java Record Typed key for an Apache Ignite Cache & got the below error.

Anyone else tried using record types & seen this?

Does this mean custom handling of marshalling is needed when using record types? I am using Java 17.0.12 (openjdk version "17.0.12" 2024-07-16) & Gridgain ignite 8.8.39.

java.lang.UnsupportedOperationException: can't get field offset on a record class: private final long *...TestIgniteCache$TestKey.ttlInMillis at jdk.unsupported/sun.misc.Unsafe.objectFieldOffset(Unknown Source) at org.apache.ignite.internal.util.GridUnsafe.objectFieldOffset(GridUnsafe.java:1193) at org.apache.ignite.internal.binary.BinaryFieldAccessor$AbstractPrimitiveAccessor.(BinaryFieldAccessor.java:223) at org.apache.ignite.internal.binary.BinaryFieldAccessor$LongPrimitiveAccessor.(BinaryFieldAccessor.java:387) at org.apache.ignite.internal.binary.BinaryFieldAccessor.create(BinaryFieldAccessor.java:75) at org.apache.ignite.internal.binary.BinaryClassDescriptor.(BinaryClassDescriptor.java:368) at org.apache.ignite.internal.binary.BinaryClassDescriptor.(BinaryClassDescriptor.java:155) at org.apache.ignite.internal.binary.BinaryContext.createDescriptorForClass(BinaryContext.java:648) at org.apache.ignite.internal.binary.BinaryContext.descriptorForClass(BinaryContext.java:606) at org.apache.ignite.internal.binary.BinaryWriterExImpl.marshal0(BinaryWriterExImpl.java:181) at org.apache.ignite.internal.binary.BinaryWriterExImpl.marshal(BinaryWriterExImpl.java:164) at org.apache.ignite.internal.binary.BinaryWriterExImpl.marshal(BinaryWriterExImpl.java:151) at org.apache.ignite.internal.binary.GridBinaryMarshaller.marshal(GridBinaryMarshaller.java:250) at org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl.marshalToBinary(CacheObjectBinaryProcessorImpl.java:506) at org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl.toBinary(CacheObjectBinaryProcessorImpl.java:1360) at org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl.toCacheKeyObject(CacheObjectBinaryProcessorImpl.java:1137) at org.apache.ignite.internal.processors.cache.GridCacheContext.toCacheKeyObject(GridCacheContext.java:1841) at org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridDhtAtomicCache$12.apply(GridDhtAtomicCache.java:476) at org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridDhtAtomicCache$12.apply(GridDhtAtomicCache.java:474) at org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridDhtAtomicCache.asyncOp(GridDhtAtomicCache.java:766) at org.apache.ignite.internal.processors.cache.distributed.dht.atomic.GridDhtAtomicCache.getAsync(GridDhtAtomicCache.java:474) at org.apache.ignite.internal.processors.cache.GridCacheAdapter.get0(GridCacheAdapter.java:4376) at org.apache.ignite.internal.processors.cache.GridCacheAdapter.get(GridCacheAdapter.java:4357) at org.apache.ignite.internal.processors.cache.GridCacheAdapter.get(GridCacheAdapter.java:1432) at org.apache.ignite.internal.processors.cache.IgniteCacheProxyImpl.get(IgniteCacheProxyImpl.java:1116) at org.apache.ignite.internal.processors.cache.GatewayProtectedCacheProxy.get(GatewayProtectedCacheProxy.java:637) at ..**..cache.TestIgniteCache.get(TestIgniteCache.java:123)

Here is the record typed key class definition:

public static record TestKey<K>(K k, long ttlInMillis) {

    // default is 5 minutes for now.
    private static final long defaultTTLInMillis = 300000L;

    /**
     * @param k
     * @param ttlInMillis
     * 
     * A key with the specified TTL in Milliseconds
     */
    public TestKey {
        if (Objects.isNull(k)) { 
            throw new IllegalArgumentException("Key must not be null!");
        }
        if (0 >= ttlInMillis) { 
            throw new IllegalArgumentException("ttlInMillis must not be zero or negative!");
        }
    }

    /**
     * @param k
     * 
     * A key that has the default TTL as returned by {@link TestKey#defaultTTLInMillis()}
     * 
     */
    public TestKey (K k) {
        this(k, defaultTTLInMillis);
    }

    /**
     * @return the defaultttlinmillis
     */
    public static final long defaultTTLInMillis() {
        return defaultTTLInMillis;
    }

}

Solution

  • Unfortunately, record types are not currently supported out of the box. As you suggest, you'd need a custom marshaller. (The default marshaller instantiates a default object and then sets its properties individually. Records are immutable.)