1
votes

Every time I try to use the Ignite Spring API and Ignite SQL API interchangeably, I get class cast exceptions or "no sql table found for xxxx"

This happened because I created a cache using ignite spring and tried to consume the data using Ignite SQL API, or vice-versa:

@Configuration
@EnableIgniteRepositories("local.teste.is.api.repositories")
public class SpringAppCfg {

    @Bean
    public Ignite igniteInstance() {
        IgniteConfiguration cfg = new IgniteConfiguration();

        cfg.setIgniteInstanceName("springDataNode");
        cfg.setPeerClassLoadingEnabled(true);
        cfg.setClientMode(true);

        ...

        // Defining and creating a new cache to be used by Ignite Spring Data
        // repository.
        CacheConfiguration ccfg = new CacheConfiguration("SQL_PUBLIC_SAMPLETYPE3");

        // Setting SQL schema for the cache.
        ccfg.setIndexedTypes(Integer.class, SampleType.class);

        cfg.setCacheConfiguration(ccfg);

        Ignite ignite = Ignition.start(cfg);

        IgniteCache cache = ignite.getOrCreateCache(ccfg);

        SqlQuery sql = new SqlQuery(SampleType.class, "true");

        try (QueryCursor<Entry<Integer, SampleType>> cursor = cache.query(sql)) {
              for (Entry<Integer, SampleType> e : cursor)
                System.out.println(e.getValue().toString());
            }


        return ignite;
    }

SampleTypeRepository:

package local.teste.is.api.repositories;

import org.apache.ignite.springdata.repository.IgniteRepository;
import org.apache.ignite.springdata.repository.config.RepositoryConfig;

import local.al40.is.api.entities.SampleType;

@RepositoryConfig(cacheName = "SQL_PUBLIC_SAMPLETYPE")
public interface SampleTypeRepository extends IgniteRepository<SampleType, Integer>  {

    public SampleType getSampleTypeBySampleTypeId(Integer id);

}

Everything using ignite Spring works, including saving and reading data:

public class Application {

private static AnnotationConfigApplicationContext dataCtx;
private static SampleTypeRepository repo;

public static void main(String[] args) throws Exception {

    dataCtx = new AnnotationConfigApplicationContext();

    // Explicitly registering Spring configuration.
    dataCtx.register(SpringAppCfg.class);
    dataCtx.refresh();

    repo = dataCtx.getBean(SampleTypeRepository.class);

    System.out.println(repo);

    SampleType s = new SampleType(1, "teste");

    repo.save(s.getSampleTypeId(), s);

    System.out.println(repo.getSampleTypeBySampleTypeId(1).getSampleTypeName());

This happens if I create an Ignite SQL table via DDL and try to consume it via Ignite Spring, giving me a ClassCastException like "...ignite.IgniteRepositoryImpl#123456 cannot be casted to SampleType.class". This leads me to believe that this is a problem related to serialization. It also gives me "no sql table found for xxxx" if I create the table via Ignite Spring and tried to query it. Has someone tried to integrate these two perspectives? The examples I found online assume only caches created using Ignite Spring, and Ignite's documentation makes it seem that it this interchange is possible and transparent. However, apparently, it is not, unless I'm forgetting something.

Best regards,

Carlos Costa

2
Can you show how SampleTypeRepository type is defined? - alamar

2 Answers

4
votes

Okay, I solved my problem. Thanks everyone for your help. In an attempt to further clarify my rather complex doubt, I will write the following guidelines that should be taken into consideration if one is trying to use Ignite SQL and Ignite Spring interchangeably:

Option 1) Create caches via Ignite Spring:

a) Clearly define the cache name in the repository class:

...
@RepositoryConfig(cacheName = "My Cache Name")
public interface SampleTypeRepository extends IgniteRepository<SampleType, Integer>  {

    public SampleType getSampleTypeBySampleTypeId(Integer id);

}

b) Define the cache and indexed when configuring your Ignite instance in the Spring app:

...
CacheConfiguration ccfg = new CacheConfiguration("My Chache Name");

// Setting SQL schema for the cache.
ccfg.setIndexedTypes(Integer.class, SampleType.class);

config.setCacheConfiguration(ccfg);

Ignite ignite = Ignition.start(config);
...

c) Query it, but be aware that for some reason the SQL table name is "SampleType" not "My Cache Name". I don't know ehy, but it seems to be some default behavior that I did not find explicitly in the Ignite Spring documentation. Otherwise you may get "no SQL table found for ":

...
IgniteCache cache = ignite.cache("My Chache Name");

        SqlFieldsQuery  sql = new SqlFieldsQuery("select * from SampleType");
        try (QueryCursor<List<?>> cursor = cache.query(sql)) {
              for (List<?> e : cursor)
                System.out.println(e.get(1));
            }

Option 2) Create caches via SQL DDL:

a) Create your SQL table/cache by clearly defining the cache_name, key_type and value_type, using fully qualified package names for the classes corresponding to the key and value types:

CREATE TABLE IF NOT EXISTS SampleType(SampleTypeID int, SampleTypeName varchar, PRIMARY KEY (SampleTypeID)) WITH "cache_name=mycachename, key_type=java.lang.Integer, value_type=local.teste.is.api.entities.SampleType";

b) To insert data, via ignite Spring works like a charm using the API methods shown in the documentation. However, inserting via DDL or JDBC you need to clearly identify the _KEY attribute (an hidden attribute apparently :P):

INSERT INTO SampleType(_KEY, SAMPLETYPEID, SAMPLETYPENAME) VALUES(?,?,?)

Then, I think you can use these APIs interchangeably.

Best regards, Carlos Costa

0
votes

Have you tried importing Cache.Entry instead of Map.Entry? Unfortunately I can't see your import lists but I suspect you can replace latter with former, get your code to function.