This discussion is archived
5 Replies Latest reply: Oct 2, 2013 12:47 AM by Jonathan.Knight RSS

EqualsFilter on cache to query the object with parameterized accessor method

1007895 Newbie
Currently Being Moderated

Hi,

 

I have the requirement to retrieve the data from cache using filters.

My object has deep graph hierarchy as below and I have to retreive top level object from cache by comparing the loginId which is at the bottom with value.

For that, I have used Filter AlternateIdFilter = new EqualsFilter("getChannelInfos.getChannelInfo.get(0).getCredential.getLoginId", "test");

When I try to execute the code, coherence throwing exceptions as

at java.lang.Thread.run(Thread.java:680) [na:1.6.0_43]

Caused by: java.lang.RuntimeException: Missing or inaccessible method: java.util.ArrayList.get(0)()

 

Can you please help me to fix this issue? Do I need to write any custom handlers to handle this type of code?

Object sample

=============

class FICustomer{

private ChannelInfos channelInfo;

public ChannelInfos getChannelInfos() {

        return channelInfos;

    }

}

 

public class ChannelInfos

protected List<ChannelInfo> channelInfo;

public List<ChannelInfo> getChannelInfo() {

        if (channelInfo == null) {

            channelInfo = new ArrayList<ChannelInfo>();

        }

        return this.channelInfo;

    }

}

public class ChannelInfo{

Credential credential;

public Credential getCredential() {

        return credential;

    }

}

public class Credential{

String loginId;

}

  • 1. Re: EqualsFilter on cache to query the object with parameterized accessor method
    Jonathan.Knight Expert
    Currently Being Moderated

    Hi

     

    You need to write a custom ValueExtractor to extract the LoginId value. Here is an example...

     

    import com.tangosol.io.pof.annotation.Portable;
    import com.tangosol.util.ValueExtractor;
    @Portable
    public class LoginIdExtractor implements ValueExtractor {
        public LoginIdExtractor() {
        }
        @Override
        public Object extract(Object value) {
            FICustomer customer = (FICustomer) value;
            return customer.getChannelInfos().getChannelInfo().get(0).getCredential().getLoginId();
        }
    }

     

    Then you can run it like this

     

    Filter AlternateIdFilter = new EqualsFilter(new LoginIdExtractor(), "test");

     

    I have assumed you are using POF in your cluster so the LoginIdExtractor class is annotated with @Portable and you would need to add it to your POF configuration file.

     

    If you are using POF to serialize your domain objects into the cache then you could make a more efficient extractor than the one above using POF extractors.

     

    JK

  • 2. Re: EqualsFilter on cache to query the object with parameterized accessor method
    1007895 Newbie
    Currently Being Moderated

    HI JK,

     

    Thank you much for the inputs. It is working fine now.

    But I have another question that, to improve the performance  in looking up the cache with filter key, I am thinking of addding the key to Cache Index for the above scenario.

     

    But it is not accepting and throwing error as ' missing or inaccessible method java.util.ArrayList.get(0) exception

    NamedCache cache = CacheFactory.getCache(CACHE_NAME);

         cache.addIndex(new ChainedExtractor("getChannelInfos.getChannelInfo.get(0).getCredential.getLoginId"),false,null);

     

    Can you please provide your thoughts on how can I accomplish the above work?  Or suggest me the better approach with examples?

     

    Thanks in Advance.

  • 3. Re: EqualsFilter on cache to query the object with parameterized accessor method
    user639604 Journeyer
    Currently Being Moderated

    Use the new LoginIdExtractor() you have now for cache.addIndex().

  • 4. Re: EqualsFilter on cache to query the object with parameterized accessor method
    1007895 Newbie
    Currently Being Moderated

    Thanks.It is working.

    Regarding, adding new extractor in pof config file,  I have copied all the content from coherence-pof-config.xml to my custom pof file in class path.

    And added newly written extractor in my custom POF file.

     

    Do I need to copy the whole content from coherence JAR file or I can add just the new content?  Will coherence library can merge the contents (coherence JAR file POF config +  custom POF config file) during execution?

     

    Thanks.

  • 5. Re: EqualsFilter on cache to query the object with parameterized accessor method
    Jonathan.Knight Expert
    Currently Being Moderated

    Hi,

     

    A couple of points on the posts above.

     

    1. If you use the LoginIdExtractor for an Index you will need to add equals() and hashCode() methods to the class otherwise Coherence will not be able to match the extractor when in a Filter to the Index.

    import com.tangosol.io.pof.annotation.Portable; 
    import com.tangosol.util.ValueExtractor; 
    @Portable 
    public class LoginIdExtractor implements ValueExtractor { 
        public LoginIdExtractor() { 
        } 
        @Override 
        public Object extract(Object value) { 
            FICustomer customer = (FICustomer) value; 
            return customer.getChannelInfos().getChannelInfo().get(0).getCredential().getLoginId(); 
        }
        @Override
        public boolean equals(Object obj)
        {
            return obj.getClass().equals(LoginIdExtractor.class);
        }
        @Override
        public int hashCode()
        {
            return LoginIdExtractor.class.hashCode();
        }
    } 

     

    There is no state in the class so the equals() and hashCode() methods are very simple.

     

    2. Regarding copying all of the contents of the coherence-pof-config.xml into your POF configuration - this is wrong and not how you do it. You just need to include the Coherence configuration inside your configuration like this

     

    <pof-config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns="http://xmlns.oracle.com/coherence/coherence-pof-config"
      xsi:schemaLocation="http://xmlns.oracle.com/coherence/coherence-pof-config
      coherence-pof-config.xsd">
      <user-type-list>
        <include>coherence-pof-config.xml</include>
        <user-type>
          <type-id>1001</type-id>
          <class-name>LoginIdExtractor</class-name>
        </user-type>
      </user-type-list>
    </pof-config>

     

    You can see on line 6 the <include> element that includes the coherence-pof-config.xml file. You can have multiple include elements if you want to include other POF configuration files.

     

    3. There is a way to use a ReflectionExtractor and pass parameters to the method instead of using custom extractors. As I said though, it is more efficient to use POF extractors as you will not be deserializing everything in the cache.

    In your case the methods you want to chain together are getChannelInfos.getChannelInfo.get(0).getCredential.getLoginId


    As you have seen trying to do that in a single String breaks as the get(0) does not work.

     

    You will see that ReflectionExtractor has a constructor that takes both the method name and an array of parameters

     

    public ReflectionExtractor(String sMethod, Object[] aoParam)

     

    So to use this in your case you can combine the ChainedExtractor and ReflectionExtractor to get what you want

     

    ValueExtractor extractor = new ChainedExtractor(
            new ValueExtractor[]{
                    new ChainedExtractor("getChannelInfos.getChannelInfo"),
                    new ReflectionExtractor("get", new Object[]{0}),
                    new ChainedExtractor("getCredential.getLoginId"),
            }
    );
    cache.addIndex(extractor, false, null);
    Filter filter = new EqualsFilter(extractor, "test");
    Set entries = cache.entrySet(filter);

     

    There is a constructor for ChainedExtractor that takes an array of ValueExtractor instances to  be chained together so we use this as our main extractor. In the array of extractors we first use a ChainedExtractor to extract the result of getChannelInfos.getChannelInfo then we use a ReflectionExtractor to extract get(0) by specifying that the method name is get and the Object array of parameters just contains the single 0 for the parameter to pass to the get method. Finally we have another ChainedExtractor for the rest of the methods getCredential.getLoginId

     

    JK

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points