While trying to migrate my application from Java8,Springboot v1.x to Java21,Springboot v3.2.0, I encountered the following issue while trying to configure cassandra in my application:
> Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cassandraMappingContext' defined in class path resource [com/blabla/main/CassandraConfig.class]: Unable to make field private long java.util.GregorianCalendar.gregorianCutover accessible: module java.base does not "opens java.util" to unnamed module @61862a7f
> at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1775)
> at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601)
> at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:523)
> at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325)
> at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
> at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323)
> at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:224)
> at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1321)
> at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1282)
> at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveBean(DefaultListableBeanFactory.java:484)
> at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:339)
> at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:332)
> at org.springframework.data.cassandra.config.AbstractSessionConfiguration.requireBeanOfType(AbstractSessionConfiguration.java:103)
> at org.springframework.data.cassandra.config.AbstractCassandraConfiguration.cassandraConverter(AbstractCassandraConfiguration.java:76)
> at com.blabla.main.CassandraConfig$$SpringCGLIB$$0.CGLIB$cassandraConverter$20(<generated>)
> at com.blabla.main.CassandraConfig$$SpringCGLIB$$FastClass$$0.invoke(<generated>)
> at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258)
> at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331)
> at com.blabla.main.CassandraConfig$$SpringCGLIB$$0.cassandraConverter(<generated>)
> at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
> at java.base/java.lang.reflect.Method.invoke(Method.java:580)
> at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140)
> 142 common frames omitted
> Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private long java.util.GregorianCalendar.gregorianCutover accessible: module java.base does not "opens java.util" to unnamed module @61862a7f
> at java.base/java.lang.reflect.AccessibleObject.throwInaccessibleObjectException(AccessibleObject.java:391)
> at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:367)
> at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:315)
> at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:183)
> at java.base/java.lang.reflect.Field.setAccessible(Field.java:177)
> at org.springframework.util.ReflectionUtils.makeAccessible(ReflectionUtils.java:804)
> at org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.doWith(AbstractMappingContext.java:616)
> at org.springframework.util.ReflectionUtils.doWithFields(ReflectionUtils.java:728)
> at org.springframework.data.mapping.context.AbstractMappingContext.doAddPersistentEntity(AbstractMappingContext.java:471)
> at org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:424)
> at org.springframework.data.cassandra.core.mapping.CassandraMappingContext.addPersistentEntity(CassandraMappingContext.java:326)
> at org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.lambda$createAndRegisterProperty$3(AbstractMappingContext.java:671)
> at java.base/java.lang.Iterable.forEach(Iterable.java:75)
> at org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.createAndRegisterProperty(AbstractMappingContext.java:668)
> at org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.doWith(AbstractMappingContext.java:622)
> at org.springframework.util.ReflectionUtils.doWithFields(ReflectionUtils.java:728)
> at org.springframework.data.mapping.context.AbstractMappingContext.doAddPersistentEntity(AbstractMappingContext.java:471)
> at org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:424)
> at org.springframework.data.cassandra.core.mapping.CassandraMappingContext.addPersistentEntity(CassandraMappingContext.java:326)
> at org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.lambda$createAndRegisterProperty$3(AbstractMappingContext.java:671)
> at java.base/java.lang.Iterable.forEach(Iterable.java:75)
> at org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.createAndRegisterProperty(AbstractMappingContext.java:668)
> at org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.doWith(AbstractMappingContext.java:622)
> at org.springframework.util.ReflectionUtils.doWithFields(ReflectionUtils.java:728)
> at org.springframework.data.mapping.context.AbstractMappingContext.doAddPersistentEntity(AbstractMappingContext.java:471)
> at org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:424)
> at org.springframework.data.cassandra.core.mapping.CassandraMappingContext.addPersistentEntity(CassandraMappingContext.java:326)
> at org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:384)
> at java.base/java.lang.Iterable.forEach(Iterable.java:75)
> at org.springframework.data.cassandra.CassandraManagedTypes.forEach(CassandraManagedTypes.java:81)
> at org.springframework.data.mapping.context.AbstractMappingContext.initialize(AbstractMappingContext.java:563)
> at org.springframework.data.cassandra.core.mapping.CassandraMappingContext.initialize(CassandraMappingContext.java:114)
> at org.springframework.data.mapping.context.AbstractMappingContext.afterPropertiesSet(AbstractMappingContext.java:555)
> at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1822)
> at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1771)
> 163 common frames omitted
The CassandraConfig.java implementation:
@Configuration
@EnableCassandraRepositories(basePackages = "com.blabla")
public class CassandraConfig extends AbstractCassandraConfiguration {
@Value("${cassandra.contactpoints}")
private String contactPoints;
@Value("${cassandra.port}")
private int port;
@Value("${cassandra.keyspace}")
private String keySpace;
@Value("${cassandra.basePackages}")
private String basePackages;
@Value("${cassandra.cluster}")
private String clusterName;
@Value("${cassandra.username}")
private String username;
@Value("${cassandra.consistency}")
private String consistency;
private String password;
private static final Logger log = LoggerFactory.getLogger(CassandraConfig.class);
@PostConstruct
public void init(){
// logic to get my password to connect with cassandra from another repo.
}
protected AuthProvider getAuthProvider() {
return new PlainTextAuthProvider(username, password);
}
@Override
protected String getKeyspaceName() {
return keySpace;
}
@Override
protected String getContactPoints() {
return contactPoints;
}
@Override
protected int getPort() {
return port;
}
@Override
public SchemaAction getSchemaAction() {
return SchemaAction.CREATE_IF_NOT_EXISTS;
}
@Override
public String[] getEntityBasePackages() {
return new String[] {basePackages};
}
@Override
protected String getClusterName() {
return clusterName;
}
@Bean
public QueryLogger queryLogger(Cluster cluster) {
QueryLogger queryLogger = QueryLogger.builder().build();
cluster.register(queryLogger);
return queryLogger;
}
protected AddressTranslator getAddressTranslator() {
return new CassandraAddressTranslator();
}
protected QueryOptions getQueryOptions() {
QueryOptions queryOptions = new QueryOptions();
queryOptions.setConsistencyLevel(ConsistencyLevel.valueOf(consistency));
return queryOptions;
}
}
I am using the following dependency for cassandra:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-cassandra</artifactId>
<version>4.3.3</version>
</dependency>
I am unable to find the solution how my code can access the private field gregorianCutover from class GregorianCalendar.
At a number of places, I found a solution to use the following JVM arguments:
java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED
But I also got to know that this is not a safe and advisable approach to be followed.
Can someone please suggest a safe and clean approach to handle this issue?
I am using the latest version of all the dependencies.
GregorianCalendarhas a publicgetGregorianChangemethod that returns the cutover value as aDate-12219292800000Lall the time. Besides, it’s better to use thejava.timeAPI instead of the legacyCalendaranyway…