Issue with querying nested collections with portable in hazelcast 3.6.3

155 views
Skip to first unread message

Dharam Thacker

unread,
Jun 10, 2016, 12:29:09 AM6/10/16
to Hazelcast
Hi Team,

I have extended this example:

My Limb class looks like as shown below. With that I am trying to extract row based on columnname and columnvalue, but it fails. Could some one help here?

Map contents :
        map.put(1, new PersonPortable("Georg", getTuple("left-leg","LL"), getTuple("right-leg","RL")));
        map.put(2, new PersonPortable("Peter", getTuple("left-hand","LH"), getTuple("right-hand","RH")));
        map.put(3, new PersonPortable("Hans", getTuple("left-leg","LL"), getTuple("right-leg","RL")));
        map.put(4, new PersonPortable("Stefanie", getTuple("left-arm","LA"), getTuple("right-arm","RA")));

Query :

Case1:
 Predicate p = new SqlPredicate("limbs[any].name == right-leg and limbs[any].value == RL");

Exception:
Caused by: java.lang.IllegalArgumentException: path cannot be null or empty
at com.hazelcast.util.Preconditions.checkHasText(Preconditions.java:43)
at com.hazelcast.internal.serialization.impl.PortablePathCursor.init(PortablePathCursor.java:45)

Case2:
Predicate p = new SqlPredicate("limbs[any].name == right-leg and value == RL");

Result : Empty Person results :(

Case3:

I tried with ValueExtractor as well saying "LimbNameExtractor" and "LimbValueExtractor", but it fails with same. 

Limb class:
public static class LimbPortable implements Portable {

        public static final int CLASS_ID = 1001;

        String name;
        String value;

        public LimbPortable() {
        }

        public LimbPortable(String name,String value) {
            this.name = name;
            this.value = value;
        }

        public static LimbPortable getTuple(String name,String value) {
            return new LimbPortable(name,value);
        }

        @Override
        public int getFactoryId() {
            return PersonPortableFactory.FACTORY_ID;
        }

        @Override
        public int getClassId() {
            return CLASS_ID;
        }

        @Override
        public void writePortable(PortableWriter out) throws IOException {
            out.writeUTF("name", name);
            out.writeUTF("value", value);
        }

        @Override
        public void readPortable(PortableReader in) throws IOException {
            name = in.readUTF("name");
            value = in.readUTF(value);
        }
    }

Jaromir Hamala

unread,
Jun 10, 2016, 11:04:52 AM6/10/16
to Hazelcast
Hi Dharam,

you LimbPortable class has a bug in the `readPortable()` method.

instead of 
`value = in.readUTF(value);`  

there should be 
`in.readUTF("value");`  <-- see the value is a string literal, not a variable. :)

That being said we should improve the error message. 

Cheers,
Jaromir

Dharam Thacker

unread,
Jun 11, 2016, 1:39:19 PM6/11/16
to Hazelcast
Thank you Jaromir!

One more help. I tried though same with IdentifiedDataSerializable with exactly same example. LimbPortable(name,value)

But in that case, I am getting following exception,

com.hazelcast.query.QueryException: java.lang.IllegalArgumentException: There is no suitable accessor for 'name' on class 'interface com.hazelcast.nio.serialization.IdentifiedDataSerializable'
at com.hazelcast.query.impl.getters.ReflectionHelper.createGetter(ReflectionHelper.java:176)
at com.hazelcast.query.impl.getters.Extractors.instantiateGetter(Extractors.java:125)
at com.hazelcast.query.impl.getters.Extractors.getGetter(Extractors.java:102)
at com.hazelcast.query.impl.getters.Extractors.extract(Extractors.java:64)
at com.hazelcast.query.impl.QueryableEntry.extractAttributeValueFromTargetObject(QueryableEntry.java:144)
at com.hazelcast.query.impl.QueryableEntry.extractAttributeValue(QueryableEntry.java:82)
at com.hazelcast.query.impl.QueryableEntry.getAttributeValue(QueryableEntry.java:48)
at com.hazelcast.query.impl.predicates.AbstractPredicate.readAttributeValue(AbstractPredicate.java:130)
at com.hazelcast.query.impl.predicates.AbstractPredicate.apply(AbstractPredicate.java:55)
at com.hazelcast.query.impl.predicates.AndPredicate.apply(AndPredicate.java:115)
at com.hazelcast.map.impl.query.MapQueryEngineImpl.queryTheLocalPartition(MapQueryEngineImpl.java:285)
at com.hazelcast.map.impl.query.MapQueryEngineImpl.querySequential(MapQueryEngineImpl.java:187)
at com.hazelcast.map.impl.query.MapQueryEngineImpl.queryUsingFullTableScan(MapQueryEngineImpl.java:176)
at com.hazelcast.map.impl.query.MapQueryEngineImpl.queryLocalPartitions(MapQueryEngineImpl.java:131)
at com.hazelcast.map.impl.query.QueryOperation.run(QueryOperation.java:51)
at com.hazelcast.spi.impl.operationservice.impl.OperationRunnerImpl.run(OperationRunnerImpl.java:172)
at com.hazelcast.spi.impl.operationexecutor.classic.ClassicOperationExecutor.runOnCallingThread(ClassicOperationExecutor.java:392)
at com.hazelcast.spi.impl.operationexecutor.classic.ClassicOperationExecutor.runOnCallingThreadIfPossible(ClassicOperationExecutor.java:345)
at com.hazelcast.spi.impl.operationservice.impl.Invocation.doInvokeLocal(Invocation.java:259)
at com.hazelcast.spi.impl.operationservice.impl.Invocation.doInvoke(Invocation.java:243)
at com.hazelcast.spi.impl.operationservice.impl.Invocation.invokeInternal(Invocation.java:210)
at com.hazelcast.spi.impl.operationservice.impl.Invocation.invoke(Invocation.java:180)
at com.hazelcast.spi.impl.operationservice.impl.InvocationBuilderImpl.invoke(InvocationBuilderImpl.java:49)
at com.hazelcast.client.impl.protocol.task.map.AbstractMapQueryMessageTask.createInvocations(AbstractMapQueryMessageTask.java:109)
at com.hazelcast.client.impl.protocol.task.map.AbstractMapQueryMessageTask.invokeOnMembers(AbstractMapQueryMessageTask.java:90)
at com.hazelcast.client.impl.protocol.task.map.AbstractMapQueryMessageTask.call(AbstractMapQueryMessageTask.java:79)
at com.hazelcast.client.impl.protocol.task.AbstractCallableMessageTask.processMessage(AbstractCallableMessageTask.java:34)
at com.hazelcast.client.impl.protocol.task.AbstractMessageTask.initializeAndProcessMessage(AbstractMessageTask.java:118)
at com.hazelcast.client.impl.protocol.task.AbstractMessageTask.run(AbstractMessageTask.java:98)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
at com.hazelcast.util.executor.HazelcastManagedThread.executeRun(HazelcastManagedThread.java:76)
at com.hazelcast.util.executor.HazelcastManagedThread.run(HazelcastManagedThread.java:92)
Caused by: java.lang.IllegalArgumentException: There is no suitable accessor for 'name' on class 'interface com.hazelcast.nio.serialization.IdentifiedDataSerializable'
at com.hazelcast.query.impl.getters.ReflectionHelper.createGetter(ReflectionHelper.java:168)
... 33 more

Snippet for PersonIdentifiedSerializable:

@Override
public void writeData(ObjectDataOutput out) throws IOException {
out.writeUTF(name);
out.writeInt(limbs.length);
for (IdentifiedDataSerializable i : limbs) {
out.writeObject(i);
}
}

@Override
public void readData(ObjectDataInput in) throws IOException {
name = in.readUTF();
size = in.readInt();
limbs = new IdentifiedDataSerializable[size];
for (int i = 0; i < size; i++) {
limbs[i] = in.readObject();
}
}


Thanks,
Dharam

Jaromir Hamala

unread,
Jun 12, 2016, 2:52:27 AM6/12/16
to Hazelcast
Hi Dharam,

I suppose this is your Person class:

static final class PersonPortable implements DataSerializable {

public static final int CLASS_ID = 1000;

String name;
IdentifiedDataSerializable limbs[];

Can you try to change the type of the limbs[] field from IdentifiedDataSerializable to whatever type you are using for a Limb? 

Cheers,
Jaromir

Dharam Thacker

unread,
Jun 12, 2016, 4:52:18 AM6/12/16
to Hazelcast
Superb! That worked :)

Thanks a lot Jaromir.

Jaromir Hamala

unread,
Jun 12, 2016, 5:42:06 AM6/12/16
to Hazelcast
That's great to hear, Happy Hazelcasting! ;-)
Reply all
Reply to author
Forward
0 new messages