Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document with LocalDateTime field doesn't work in Java 17 #4237

Open
adubrov opened this issue Nov 21, 2022 · 14 comments
Open

Document with LocalDateTime field doesn't work in Java 17 #4237

adubrov opened this issue Nov 21, 2022 · 14 comments
Assignees
Labels
status: feedback-provided Feedback has been provided type: bug A general bug

Comments

@adubrov
Copy link

adubrov commented Nov 21, 2022

Migrated very simple java application from Java 11 to Java 17. Have singe Document

@Document
@Data
@NoArgsConstructor
public class SyncTask {

  @Id
  private ObjectId id;

  @Indexed
  private String taskId;
  
  private LocalDateTime startedOn;

}

And getting issue on start up

Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make private java.time.LocalDateTime(java.time.LocalDate,java.time.LocalTime) accessible: module java.base does not "opens java.time" to unnamed module @757acd7b
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
	at java.base/java.lang.reflect.Constructor.checkCanSetAccessible(Constructor.java:188)
	at java.base/java.lang.reflect.Constructor.setAccessible(Constructor.java:181)
	at org.springframework.util.ReflectionUtils.makeAccessible(ReflectionUtils.java:202)
	at org.springframework.data.mapping.PreferredConstructor.<init>(PreferredConstructor.java:53)
	at org.springframework.data.mapping.model.PreferredConstructorDiscoverer$Discoverers.buildPreferredConstructor(PreferredConstructorDiscoverer.java:224)
	at org.springframework.data.mapping.model.PreferredConstructorDiscoverer$Discoverers.access$200(PreferredConstructorDiscoverer.java:93)
	at org.springframework.data.mapping.model.PreferredConstructorDiscoverer$Discoverers$1.discover(PreferredConstructorDiscoverer.java:136)
	at org.springframework.data.mapping.model.PreferredConstructorDiscoverer.discover(PreferredConstructorDiscoverer.java:81)
	at org.springframework.data.mapping.model.InstanceCreatorMetadataDiscoverer.discover(InstanceCreatorMetadataDiscoverer.java:83)
	at org.springframework.data.mapping.model.BasicPersistentEntity.<init>(BasicPersistentEntity.java:113)
	at org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity.<init>(BasicMongoPersistentEntity.java:84)
	at org.springframework.data.mongodb.core.mapping.MongoMappingContext.createPersistentEntity(MongoMappingContext.java:100)
	at org.springframework.data.mongodb.core.mapping.MongoMappingContext.createPersistentEntity(MongoMappingContext.java:41)
	at org.springframework.data.mapping.context.AbstractMappingContext.doAddPersistentEntity(AbstractMappingContext.java:430)
	at org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:406)
	at org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.lambda$createAndRegisterProperty$3(AbstractMappingContext.java:630)
	at java.base/java.lang.Iterable.forEach(Iterable.java:75)
	at org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.createAndRegisterProperty(AbstractMappingContext.java:627)
	at org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.doWith(AbstractMappingContext.java:581)
	at org.springframework.util.ReflectionUtils.doWithFields(ReflectionUtils.java:714)
	at org.springframework.data.mapping.context.AbstractMappingContext.doAddPersistentEntity(AbstractMappingContext.java:449)
	at org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:406)
	at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:291)
	at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:209)
	at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:92)
	at org.springframework.data.mapping.context.MappingContext.getRequiredPersistentEntity(MappingContext.java:74)
	at org.springframework.data.mongodb.repository.support.MongoRepositoryFactory.getEntityInformation(MongoRepositoryFactory.java:166)
	at org.springframework.data.mongodb.repository.support.MongoRepositoryFactory.getTargetRepository(MongoRepositoryFactory.java:140)
	at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:325)
	at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:323)
	at org.springframework.data.util.Lazy.getNullable(Lazy.java:231)
	at org.springframework.data.util.Lazy.get(Lazy.java:115)
	at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:329)
	at org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean.afterPropertiesSet(MongoRepositoryFactoryBean.java:119)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800)
	... 44 common frames omitted

Obviously related to this change - https://openjdk.org/jeps/396
If I remove LocalDateTime field - it starts without issue.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Nov 21, 2022
@christophstrobl christophstrobl added the for: team-attention An issue we need to discuss as a team to make progress label Nov 22, 2022
@christophstrobl
Copy link
Member

I might be missing something here. A fresh boot 3.0.5 project with the above entity works just fine on openjdk version "17.0.4.1".
Maybe you can take the time to provide a complete minimal sample (something that we can unzip or git clone, build, and deploy) that reproduces the problem.

@vikas-singh-maersk
Copy link

Hi @christophstrobl ,
I'm using boot 3.0.5 project with java version 17.0.6.When I'm trying to start the service I'm getting above mentioned exception. I'm using two mongo Db and did the configuration for that and using custom converters. It was working fine in java 11 but after upgrading it to 17, I started facing above exception.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Apr 12, 2023
@christophstrobl
Copy link
Member

@vikas-singh-maersk do you have a minimal sample (something that we can unzip or git clone, build, and deploy) that reproduces the problem at hand?

@vikas-singh-maersk
Copy link

Hi @christophstrobl ,
I have to create the minimal sample to share with you. But I have found the cause of issue. As I mentioned earlier I'm using 2 mongo DB Connection in my project and for that I'm using @EnableMongoRepositories annotation. This annotation is creating problem to access Localdatetime. If I'll remove this annotation my code works fine.
It seems like @EnableMongoRepositories annotation internally uses the MongoRepositoriesRegistrar class, which tries to create a MappingContext instance using the LocalDateTime class. Can you look into it ?

@christophe-michard
Copy link

Hi, @christophstrobl

I also faced the kind of issue reported in this ticket, when trying to update a project to Spring Boot 3+.
It is likely due to the use of ReflectionUtils.makeAccessible from spring-core, that uses setAccessible(true) internally.
Background: https://mail.openjdk.org/pipermail/jdk9-dev/2016-November/005276.html

Here is a minimal sample to reproduce the crash: https://github.com/christophe-michard/MongoSetAccessibleIssue.

Important part:

@SpringBootApplication
public class MongoSetAccessibleIssueApplication {

    public static void main(String[] args) {
        SpringApplication.run(MongoSetAccessibleIssueApplication.class, args);
    }

    public MongoSetAccessibleIssueApplication() {
        // Create a custom mongoTemplate
        // Crash happens only if we create a template with the mappingMongoConverter as second argument
        MongoDatabaseFactory mongoDbFactory = new SimpleMongoClientDatabaseFactory(MongoClients.create(), "db");
        MappingMongoConverter mappingMongoConverter = new MappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory), new MongoMappingContext());
        MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory, mappingMongoConverter);

        // Crash happens when this line is executed
        mongoTemplate.save(new MongoEntity());
    }
}

class MongoEntity {

    // We need a field that is a class from java.time package, for instance Instant, to provoke a crash.
    // Background: https://mail.openjdk.org/pipermail/jdk9-dev/2016-November/005276.html
    // Crash sample:
    //   Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make private java.time.Instant(long,int) accessible: module java.base does not "opens java.time" to unnamed module @1afd44cb
    // 	   at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354) ~[na:na]
    //	   at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297) ~[na:na]
    //	   at java.base/java.lang.reflect.Constructor.checkCanSetAccessible(Constructor.java:188) ~[na:na]
    //	   at java.base/java.lang.reflect.Constructor.setAccessible(Constructor.java:181) ~[na:na]
    //	   at org.springframework.util.ReflectionUtils.makeAccessible(ReflectionUtils.java:201) ~[spring-core-6.0.9.jar:6.0.9]
    //     at org.springframework.data.mapping.PreferredConstructor.<init>(PreferredConstructor.java:56) ~[spring-data-commons-3.1.0.jar:3.1.0]
    public Instant createdDateTime;
}

Is it enough for you to be able to investigate on the issue? 😃

@christophstrobl
Copy link
Member

@christophe-michard thanks for the reproducer!

@christophstrobl christophstrobl added the type: bug A general bug label Jun 14, 2023
@christophe-michard
Copy link

christophe-michard commented Jun 23, 2023

@christophstrobl We are using this kind of configuration to remove the autogenerated _class field, and automatically create indexes on application start.
Do you know if there is a way to do that without hitting the bug?
It is currently a blocker for us to update to Java 17 and Spring Boot 3 (whose version 2.7 is EOL in November).

@christophstrobl
Copy link
Member

I need to revisit StoreConversions and the flagging for java.time types which may take some time.
Meanwhile there's always the option of adding --add-opens=java.base/java.time=ALL-UNNAMED.

@christophstrobl
Copy link
Member

@christophe-michard you may also want to try it this way:

MongoMappingContext mappingContext = new MongoMappingContext();
MappingMongoConverter mappingMongoConverter = new MappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory), mappingContext);
mappingContext.setSimpleTypeHolder(mappingMongoConverter.getCustomConversions().getSimpleTypeHolder());
mappingContext.afterPropertiesSet();
mappingMongoConverter.afterPropertiesSet();

@christophe-michard
Copy link

@christophstrobl Thank you very much! 😄
With the lines necessary to generate the indexes and remove the _class field inserted before the afterPropertiesSet() lines (not sure of the right timing), the application passed successfully the Mongo initialization.

mappingContext.setAutoIndexCreation(true);
mappingMongoConverter.setTypeMapper(new DefaultMongoTypeMapper(null));

Now, the application stops at Solr initialization, so I will need to update solr-solrj library, and replace spring-data-solr by a custom bootstrap I guess, since it won't support Spring Boot 3 due to end of life reached.
Only after I finished that, I may be able to say if the temporary fix above is fully working, by running our test suite.

@mdeknowis
Copy link

We have the same issue

  • OffsetDateTime
  • LocalDate

hence all java.time.* classes

@wesleyegberto
Copy link

@christophe-michard you may also want to try it this way:

MongoMappingContext mappingContext = new MongoMappingContext();
MappingMongoConverter mappingMongoConverter = new MappingMongoConverter(new DefaultDbRefResolver(mongoDbFactory), mappingContext);
mappingContext.setSimpleTypeHolder(mappingMongoConverter.getCustomConversions().getSimpleTypeHolder());
mappingContext.afterPropertiesSet();
mappingMongoConverter.afterPropertiesSet();

@christophstrobl's snippet did resolve my problem.

@dlowrey
Copy link

dlowrey commented Sep 16, 2024

Hello, we also ran into this issue. We configure 2 instances of MongoTemplate in our service pointed to two separate databases, and on upgrade to Spring Boot 3 discovered auto creation of index was disabled by default.

The solutions we followed led us to this issue, and @christophstrobl's snippet seems to have resolved our issue as well. It seems this issue is > 1 year old now, is there any other more updated fix?

edit: Sorry, after commenting I see maybe a linked issue (spring-projects/spring-data-keyvalue#569) is waiting to be picked up and related.

@christophe-michard
Copy link

Follow-up from last year: our system has been updated successfully, and has been working fine since.
So the fix is stable in production for us.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: feedback-provided Feedback has been provided type: bug A general bug
Projects
None yet
Development

No branches or pull requests

8 participants