0

I have moved all the Cassandra into single class. When I tried create instance of CassandraOperations in the gemfire cache listener was getting null pointer exception.Can you please assist me on this error

I have not received any null pointer exception using spring and cassandra but getting while integrating with gemfire.

@Component  
public class CacheListener<K, V> extends CacheListenerAdapter<K, V> implements Declarable {

@Autowired
private CassandraOperations cassandraOperations;

@Override
public void init(Properties props) {

}

public void afterCreate(EntryEvent e) {
    cassandraOperations.insert(e.getNewValue());

}

@Override
public void close() {
}

}



public class CassandraConfig {
@Autowired
private Environment environment;
private static final Logger LOGGER = LoggerFactory.getLogger(CassandraConfig.class);
@Bean
public CassandraClusterFactoryBean cluster() {
    CassandraClusterFactoryBean cluster = new CassandraClusterFactoryBean();
    cluster.setContactPoints(environment.getProperty("cassandra.contactpoints"));
    cluster.setPort(Integer.parseInt(environment.getProperty("cassandra.port")));
    return cluster;
}
@Bean
public CassandraMappingContext mappingContext() {
    BasicCassandraMappingContext mappingContext = new BasicCassandraMappingContext(); 
    mappingContext.setUserTypeResolver(new SimpleUserTypeResolver(cluster().getObject(), environment.getProperty("cassandra.keyspace"))); return mappingContext;
}
@Bean
public CassandraConverter converter() {
    return new MappingCassandraConverter(mappingContext());
}
@Bean
public CassandraSessionFactoryBean session() throws Exception {
    CassandraSessionFactoryBean session = new CassandraSessionFactoryBean();
    session.setCluster(cluster().getObject());
    session.setKeyspaceName(environment.getProperty("cassandra.keyspace"));
    session.setConverter(converter());
    session.setSchemaAction(SchemaAction.NONE);
    return session;
}
@Bean
public CassandraOperations cassandraTemplate() throws Exception {
    return new CassandraTemplate(session().getObject());
}
}

Exception

[error 2017/05/05 11:16:04.874 CDT <http-nio-7878-exec-1> tid=0x5b] Exception occurred in CacheListener
java.lang.NullPointerException
    at CacheListener.afterCreate(CacheListener.java:27)
    at com.gemstone.gemfire.internal.cache.EnumListenerEvent$AFTER_CREATE.dispatchEvent(EnumListenerEvent.java:97)
    at com.gemstone.gemfire.internal.cache.LocalRegion.dispatchEvent(LocalRegion.java:8897)
    at com.gemstone.gemfire.internal.cache.LocalRegion.dispatchListenerEvent(LocalRegion.java:7376)
    at com.gemstone.gemfire.internal.cache.LocalRegion.invokePutCallbacks(LocalRegion.java:6158)
    at com.gemstone.gemfire.internal.cache.EntryEventImpl.invokeCallbacks(EntryEventImpl.java:1919)
    at com.gemstone.gemfire.internal.cache.ProxyRegionMap$ProxyRegionEntry.dispatchListenerEvents(ProxyRegionMap.java:548)
    at com.gemstone.gemfire.internal.cache.LocalRegion.basicPutPart2(LocalRegion.java:6012)
    at com.gemstone.gemfire.internal.cache.ProxyRegionMap.basicPut(ProxyRegionMap.java:232)
    at com.gemstone.gemfire.internal.cache.LocalRegion.virtualPut(LocalRegion.java:5824)
    at com.gemstone.gemfire.internal.cache.LocalRegionDataView.putEntry(LocalRegionDataView.java:118)
    at com.gemstone.gemfire.internal.cache.LocalRegion.basicPut(LocalRegion.java:5214)
    at com.gemstone.gemfire.internal.cache.LocalRegion.validatedPut(LocalRegion.java:1597)
    at com.gemstone.gemfire.internal.cache.LocalRegion.put(LocalRegion.java:1580)
    at com.gemstone.gemfire.internal.cache.AbstractRegion.put(AbstractRegion.java:327)
    at org.springframework.data.gemfire.GemfireTemplate.put(GemfireTemplate.java:189)
    at org.springframework.data.gemfire.repository.support.SimpleGemfireRepository.save(SimpleGemfireRepository.java:84)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
Vigneshwaran
  • 229
  • 1
  • 3
  • 14
  • Possible duplicate of [What is a NullPointerException, and how do I fix it?](http://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it) – Deepesh Choudhary May 05 '17 at 16:24
  • There is no exception using between cassandra and spring. Instance of Cassandra operation is not creating in gemfire listerner – Vigneshwaran May 05 '17 at 16:43
  • This is not duplicate – Vigneshwaran May 05 '17 at 16:46
  • Did you downvote my answer to you?! – John Blum May 06 '17 at 03:29
  • its not not me. Your explanation was excellent. Not yet integrated your code. – Vigneshwaran May 06 '17 at 05:19
  • Sorry, yeah that is weird. There was a panel on SO that looked like the downvote came from you, but in revisiting it, I don't think that is reliable. I upvoted your question because I think it is valid and it definitely did not deserve a -1, who ever did that, argh. Anyway, hope my answer helps, and if you have further questions, let me know. I can follow up. I am 1 of 2 leads for Spring Data Cassandra and the lead for Spring Data GemFire. Of course, I am far more knowledgeable about GemFire; still learning the ropes on Cassandra yet, :-) Cheers! – John Blum May 06 '17 at 17:31
  • Thanks John, your solutions worked. Appreciate your help. – Vigneshwaran May 07 '17 at 05:55
  • Your welcome, glad that helped. – John Blum May 08 '17 at 17:08

1 Answers1

-1

What is not apparent in your code/configuration above is how you configured your application-specific, GemFire CacheListener using Spring (Data GemFire).

I see you annotated your application CacheListener using Spring's @Component stereo-type annotation, but this does nothing without help.

Are you using Spring's Classpath component scanning functionality, or perhaps Spring's Annotation-based container configuration support? If you are using the later, you know you have to still explicitly define your application CacheListener in config (JavaConfig or XML), right?

Whenever you encounter a NullPointerException on an @Autowired component/collaborator field to inject a dependency, especially when using Spring's @Autowired annotation, it is good indication you have a configuration problem, particularly since the @Autowired annotation implies that the "dependency" (e.g. CassandraOperations) is "required" (unless you explicitly set the required attribute of the @Autowired annotation to false, which you did not; required defaults to true).

Therefore, if the CacheListener component were picked up in the scan and a dependency could not be injected (auto-wired) because no (other) bean of the specified type (e.g. CassandraOperations) was defined in the Spring application context (which it is), then Spring would throw an Exception when evaluating your configuration class(es).

Although, even your CassandraConfig class must also be annotated with Spring's @Configuration annotation or with the @Component annotation when using either Spring Classpath component scanning or Annotation-based container config. Or, it must be explicitly defined as a bean in the Spring application context if using neither.

NOTE: the naming convention (i.e. CacheListener) is not very good since it clashes with GemFire's own CacheListener interface. It would be better to call your application-specific extension/implementation perhaps, "GemFireToCassandraCacheListener"

By way of example...

import ...;

@Configuration
class GemFireConfiguration {

  @Bean
  CacheFactoryBean gemfireCache() {
    return new CacheFactoryBean();
  }

  @Bean("CassandraCache")
  PartitionedRegionFactoryBean cassandraCacheRegion() {
    PartitionedRegionFactoryBean cassandraCacheRegion = 
      new PartitionedRegionFactoryBean();

    cassandraCacheRegion.setCache(gemfireCache());
    cassandraCacheRegion.setClose(false);
    cassandraCacheRegion.setCacheListeners(
      new CacheListener[] { gemfireToCassandraCacheListener() });

    return cassandraCacheRegion;
  }

  @Bean
  GemFireToCassandraCacheListener gemfireToCassandraCacheListener() {
    return new GemFireToCassandraCacheListener();
  }
}

import ...;

@Configuration
class CassandraConfig {

  // what you have above
}

I have plenty of GemFire configuration examples here, that shows GemFire native config with Spring (Data GemFire) config, XML vs. JavaConfig vs. annotations, etc, etc.

Finally...

Technically, it might be better to use a GemFire CacheWriter, attached to the Region, rather than a CacheListener, since what you are doing (updating Cassandra on a cache create) is the intended purpose of a CacheWriter.

Of course, the CacheListener is called "after" create vs. the CacheWriter which is "before" create. However, I would say it is always better to update the "primary" data source (or "source of truth") before updating the "cache" to reflect the data source. This is applicable especially if there are constraints in the primary data source that might cause an update to fail. You would not want the cache to be updated if the primary data source could not be.

A CacheWriter is configured similarly to a CacheListener, like so...

  @Bean("CassandraCache")
  PartitionedRegionFactoryBean cassandraCacheRegion() {
    PartitionedRegionFactoryBean cassandraCacheRegion = 
      new PartitionedRegionFactoryBean();

    cassandraCacheRegion.setCache(gemfireCache());
    cassandraCacheRegion.setClose(false);
    cassandraCacheRegion.setCacheWriter(gemfireToCassandraCacheWriter());

    return cassandraCacheRegion;
  }

  @Bean
  GemFireToCassandraCacheWriter gemfireToCassandraCacheWriter(
      CassandraOperations cassandraOperations) {

    return new GemFireToCassandraCacheWriter(cassandraOperations);
  }

Where the GemFireToCassandraCacheWriter would be defined as...

class GemFireToCassandraCacheWriter extends CacheWriterAdapter {

  private CassandraOperations cassandraOperations;

  // Using constructor injection is better than field injection
  GemFireToCassandraCacheWriter(CassandraOperations cassandraOperations) {
    this.cassandraOperations = cassandraOperations;
  }

  public void beforeCreate(EntryEvent<?, ?> event) {
    cassandraOperations.insert(event.getNewValue());
  }
}

NOTE: a Region can only have 1 CacheWriter. FYI, functionally the CacheWriter is the counterpart to a CacheLoader. See the GemFire User Guide for more details. In particular, see here, here and here.

Additionally, if you are just using GemFire as a cache for state that is primarily managed in Cassandra, then you might also consider Spring's Cache Abstraction, for which Spring Data GemFire positions GemFire as a "provider" in the abstraction.

Not sure what your GemFire to Cassandra UC is all about, but food for thought.

Hope this helps!

-John

John Blum
  • 7,381
  • 1
  • 20
  • 30