Version Portable for Hazelcast : Converting Date to Long throws Exception in Predicates

526 Views Asked by At

I am trying to use com.hazelcast.nio.serialization.VersionedPortable for serialization for a Customer class. This does not support Date serialization by default. So we need to convert it to Long

@Override
public void writePortable(PortableWriter writer) throws IOException {
    if (dob != null) {
        Long dobLong = dob.getTime();
        writer.writeLong(DOB_FIELD, dobLong);
    } else {
        writer.writeLong(DOB_FIELD, -1);
    }
}

@Override
public void readPortable(PortableReader reader) throws IOException {
    if (reader.hasField(DOB_FIELD)) {
        Long dobLong = reader.readLong(DOB_FIELD);
        dob = dobLong == -1 ? null : new Date(dobLong);
    }
}

In CustomerService I have findCustomersByDob which uses com.hazelcast.query.Predicate

public Collection<Customer> findCustomersByDob(Date dobStart, Date dobEnd) {
    Predicate dobStartPredicate = Predicates.greaterEqual("dob", dobStart);
    Predicate dobEndPredicate = Predicates.lessThan("dob", dobEnd);
    Predicate andPredicate = Predicates.and(dobStartPredicate, dobEndPredicate);
    return idToCustomerMap.values(andPredicate);
}

at idToCustomerMap.values(andPredicate); I am getting the following exception.

java.lang.IllegalArgumentException: Cannot convert [Tue Jan 01 00:00:00 IST 1980] to long at com.hazelcast.query.impl.TypeConverters$LongConverter.convert(TypeConverters.java:159) at com.hazelcast.query.impl.IndexImpl.convert(IndexImpl.java:154) at com.hazelcast.query.impl.IndexImpl.getSubRecords(IndexImpl.java:148) at com.hazelcast.query.Predicates$GreaterLessPredicate.filter(Predicates.java:691) at com.hazelcast.query.Predicates$AndPredicate.filter(Predicates.java:477) at com.hazelcast.query.impl.IndexService.query(IndexService.java:97) at com.hazelcast.map.impl.operation.QueryOperation.run(QueryOperation.java:92) at com.hazelcast.spi.impl.operationservice.impl.OperationRunnerImpl.run(OperationRunnerImpl.java:137) at com.hazelcast.spi.impl.operationservice.impl.OperationRunnerImpl.run(OperationRunnerImpl.java:309) at com.hazelcast.spi.impl.operationexecutor.classic.OperationThread.processPacket(OperationThread.java:142) at com.hazelcast.spi.impl.operationexecutor.classic.OperationThread.process(OperationThread.java:115) at com.hazelcast.spi.impl.operationexecutor.classic.OperationThread.doRun(OperationThread.java:101) at com.hazelcast.spi.impl.operationexecutor.classic.OperationThread.run(OperationThread.java:76) at ------ End remote and begin local stack-trace ------.(Unknown Source) at com.hazelcast.spi.impl.operationservice.impl.InvocationFuture.resolveApplicationResponse(InvocationFuture.java:384) at com.hazelcast.spi.impl.operationservice.impl.InvocationFuture.resolveApplicationResponseOrThrowException(InvocationFuture.java:334) at com.hazelcast.spi.impl.operationservice.impl.InvocationFuture.get(InvocationFuture.java:225) at com.hazelcast.spi.impl.operationservice.impl.InvocationFuture.get(InvocationFuture.java:204) at com.hazelcast.map.impl.client.AbstractMapQueryRequest.collectResults(AbstractMapQueryRequest.java:103) at com.hazelcast.map.impl.client.AbstractMapQueryRequest.invoke(AbstractMapQueryRequest.java:77) at com.hazelcast.client.impl.client.InvocationClientRequest.process(InvocationClientRequest.java:27) at com.hazelcast.client.impl.ClientEngineImpl$ClientPacketProcessor.processRequest(ClientEngineImpl.java:463) at com.hazelcast.client.impl.ClientEngineImpl$ClientPacketProcessor.run(ClientEngineImpl.java:379) at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.lang.Thread.run(Unknown Source) at com.hazelcast.util.executor.HazelcastManagedThread.executeRun(HazelcastManagedThread.java:76) at com.hazelcast.util.executor.HazelcastManagedThread.run(HazelcastManagedThread.java:92) at ------ End remote and begin local stack-trace ------.(Unknown Source) at com.hazelcast.client.spi.impl.ClientInvocationFuture.resolveResponse(ClientInvocationFuture.java:147) at com.hazelcast.client.spi.impl.ClientInvocationFuture.get(ClientInvocationFuture.java:114) at com.hazelcast.client.spi.impl.ClientInvocationFuture.get(ClientInvocationFuture.java:89) at com.hazelcast.client.spi.ClientProxy.invoke(ClientProxy.java:151) at com.hazelcast.client.proxy.ClientMapProxy.values(ClientMapProxy.java:837) at com.foo.hazelcast.client.services.CustomerServiceImpl.findCustomersByDob(CustomerServiceImpl.java:99) at com.foo.hazelcast.client.services.CustomerServiceTest.searchCustomersByDobRange(CustomerServiceTest.java:104) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

Although it is clear the exception is because of this special handling of Date, I would like to know the exact reason for the TypeConversion here. I read that Hazelcast maintains the data in serialized form. So this should not be a problem right?

Also, how do I overcome this issue?

EDIT: I fixed this issue by passing date.getTime() in the predicates as well

public Collection<Customer> findCustomersByDob(Date dobStart, Date dobEnd) {
    Predicate dobStartPredicate = Predicates.greaterEqual("dob", dobStart.getTime());
    Predicate dobEndPredicate = Predicates.lessThan("dob", dobEnd.getTime());
    Predicate andPredicate = Predicates.and(dobStartPredicate, dobEndPredicate);
    return idToCustomerMap.values(andPredicate);
}

I am guessing it is because hazelcast maintains data in serialized form and hence confused when it is trying to compare long against the date in predicate.

Still, this approach is definitely not cleaner. Is there cleaner way to avoid this in Version Portable?

1

There are 1 best solutions below

0
On

@vinodhini-chockalingam, Portable designed to work with different languages, not just Java. So you can write a value from NodeJs & read it from Java with Portable. This is why you cannot write java.util.Date object to Portable directly. You need to convert it to a supported type.

And since you write the Date as long, Hazelcast recognizes that field as long. Only you know that this is a Date field. Then when you need to run a predicate, since you write this field as long, Hazelcast expect a long value to compare. This is the reason.