Skip to content

Illegal reflective access by org.springframework.util.ReflectionUtils #1057

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

Closed
mikereiche opened this issue Jan 20, 2021 · 5 comments · Fixed by #1167
Closed

Illegal reflective access by org.springframework.util.ReflectionUtils #1057

mikereiche opened this issue Jan 20, 2021 · 5 comments · Fixed by #1167
Assignees
Labels
type: bug A general bug

Comments

@mikereiche
Copy link
Collaborator

mikereiche commented Jan 20, 2021

This occurs for certain property types in my entities. Optional and UUID. The message that this will be denied in a future release is concerning.

This looks similar to spring-projects/spring-framework#24999. A work-around for UUID is to declare the property as Object, but store it as a UUID. This will/can result in it being set to a String by "accessor.setProperty(idProperty, generatedId);" in MappingCouchbaseConverter.writeInternal() and similarly by "accessor.setProperty(idProperty, id);" in CouchbaseTemplate.applyUpdatedId(). To accomodate that, getId() should always check for it being a String, and if so, replace it by id = UUID.fromString(id)

public UUID getId() {
	if (id != null && id.getClass()
			.equals(String.class)) {
		id = UUID.fromString((String) ((Object) id));
	}
	return (UUID)id;
}

java version 11.0.6.

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.springframework.util.ReflectionUtils (file:/Users/michaelreiche/.m2/repository/org/springframework/spring-core/5.3.3/spring-core-5.3.3.jar) to constructor java.util.Optional()
WARNING: Please consider reporting this to the maintainers of org.springframework.util.ReflectionUtils
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

with --illegal-access=debug

AccessibleObject

 private boolean checkCanSetAccessible(Class<?> caller, Class<?> declaringClass, boolean throwExceptionIfDenied)
. . .
        if (declaringModule.isOpen(pn, callerModule)) {
131:          this.logIfOpenedForIllegalAccess(caller, declaringClass); <-- warning output here
          return true;
        } else if (throwExceptionIfDenied) {

WARNING: Illegal reflective access by org.springframework.util.ReflectionUtils (file:/Users/michaelreiche/.m2/repository/org/springframework/spring-core/5.3.3/spring-core-5.3.3.jar) to constructor java.util.Optional()
WARNING: Illegal reflective access by org.springframework.util.ReflectionUtils (file:/Users/michaelreiche/.m2/repository/org/springframework/spring-core/5.3.3/spring-core-5.3.3.jar) to field java.util.Optional.value
WARNING: Illegal reflective access by org.springframework.util.ReflectionUtils (file:/Users/michaelreiche/.m2/repository/org/springframework/spring-core/5.3.3/spring-core-5.3.3.jar) to field java.util.UUID.mostSigBits
WARNING: Illegal reflective access by org.springframework.util.ReflectionUtils (file:/Users/michaelreiche/.m2/repository/org/springframework/spring-core/5.3.3/spring-core-5.3.3.jar) to field java.util.UUID.leastSigBits

public class BasicCouchbasePersistentEntity<T> extends BasicPersistentEntity<T, CouchbasePersistentProperty>
		implements CouchbasePersistentEntity<T>, EnvironmentAware {

	public BasicCouchbasePersistentEntity(final TypeInformation<T> typeInformation) {
>> 50:		super(typeInformation);
		validateExpirationConfiguration();
	}

WARNING: Illegal reflective access by org.springframework.util.ReflectionUtils (file:/Users/michaelreiche/.m2/repository/org/springframework/spring-core/5.3.3/spring-core-5.3.3.jar) to constructor java.util.Optional()
	at org.springframework.util.ReflectionUtils.makeAccessible(ReflectionUtils.java:202)
	at org.springframework.data.mapping.PreferredConstructor.<init>(PreferredConstructor.java:63)
	at org.springframework.data.mapping.model.PreferredConstructorDiscoverer$Discoverers.buildPreferredConstructor(PreferredConstructorDiscoverer.java:204)
	at org.springframework.data.mapping.model.PreferredConstructorDiscoverer$Discoverers.access$200(PreferredConstructorDiscoverer.java:91)
	at org.springframework.data.mapping.model.PreferredConstructorDiscoverer$Discoverers$1.discover(PreferredConstructorDiscoverer.java:130)
	at org.springframework.data.mapping.model.PreferredConstructorDiscoverer.discover(PreferredConstructorDiscoverer.java:79)
	at org.springframework.data.mapping.model.BasicPersistentEntity.<init>(BasicPersistentEntity.java:112)
	at org.springframework.data.mapping.model.BasicPersistentEntity.<init>(BasicPersistentEntity.java:93)
	at org.springframework.data.couchbase.core.mapping.BasicCouchbasePersistentEntity.<init>(BasicCouchbasePersistentEntity.java:50)
	at org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext.createPersistentEntity(CouchbaseMappingContext.java:74)
	at org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext.createPersistentEntity(CouchbaseMappingContext.java:37)
	at org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:368)
	at java.base/java.util.Collections$SingletonSet.forEach(Collections.java:4797)
	at org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.createAndRegisterProperty(AbstractMappingContext.java:564)

@Document
public class Person extends AbstractEntity {
	@Nullable Optional<String> firstname;

	at org.springframework.data.mapping.context.AbstractMappingContext$PersistentPropertyCreator.doWith(AbstractMappingContext.java:522)
	at org.springframework.util.ReflectionUtils.doWithFields(ReflectionUtils.java:708)
	at org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:385)
	at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:259)
	at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:202)
	at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentEntity(AbstractMappingContext.java:86)
	at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$5(RepositoryFactoryBeanSupport.java:324)
	at java.base/java.util.Optional.ifPresent(Optional.java:183)
	at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:324)
	at org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactoryBean.afterPropertiesSet(CouchbaseRepositoryFactoryBean.java:89)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1847)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1784)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:609)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:531)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)

@mikereiche mikereiche self-assigned this Jan 20, 2021
@mikereiche mikereiche added the type: bug A general bug label Jan 20, 2021
@mp911de
Copy link
Member

mp911de commented Jan 21, 2021

Optional should not be considered a PersistentEntity in the first place.

@mikereiche
Copy link
Collaborator Author

Thanks @mp911de, I was never fond of our test case with the Optional<> properties.

The problem still exists with UUID.
java.util.UUID.mostSigBits
java.util.UUID.leastSigBits

I tried encapsulating UUID in a MYUUID class, but the problem remains - the class is introspected recursively. The only "solution" I found was to declare it as Object and convert it to a UUID object if it was ever set to a String.

@mp911de
Copy link
Member

mp911de commented Jan 22, 2021

If UUID is a type directly understood by the driver, add it to CouchbaseSimpleTypes to consider UUID a simple type.

@mikereiche
Copy link
Collaborator Author

Seems that adding BigInteger and UUID converters solves those two specific problems. I am not sure how CouchbaseSimpleTypes is used.

@WritingConverter
public enum UuidToString implements Converter<UUID, String> {
INSTANCE;

@Override
public String convert(UUID source) {
  return source == null ? null : source.toString();
}

}

@ReadingConverter
public enum StringToUuid implements Converter<String, UUID> {
INSTANCE;

@Override
public UUID convert(String source) {
  return source == null ? null : UUID.fromString(source);
}

}

@WritingConverter
public enum BigIntegerToString implements Converter<BigInteger, String> {
INSTANCE;

@Override
public String convert(BigInteger source) {
  return source == null ? null : source.toString();
}

}

@ReadingConverter
public enum StringToBigInteger implements Converter<String, BigInteger> {
INSTANCE;

@Override
public BigInteger convert(String source) {
  return source == null ? null : new BigInteger(source);
}

}

@mikereiche
Copy link
Collaborator Author

mikereiche commented Aug 10, 2021

The MappingCouchbaseConverter constructers need to work like the couchbaseMappingContext Bean and mappingCouchbaseConverter Bean in AbstractCouchbaseConfiguration - which both use the CouchbaseCustomConversions. mappingCouchbaseConverter uses CouchbaseCustomConversions as the arg to setCustomConversions, and couchbaseMappingContext uses CouchbaseCustomConversions.getSimpleTypeHolder() as the arg to setSimpleTypeHolder().

  public MappingCouchbaseConverter(...){
      super(new DefaultConversionService());
      this.mappingContext = mappingContext;
      // this is how the MappingCouchbaseConverter gets the custom conversions.
      // the conversions Service gets them in afterPropertiesSet()
      CustomConversions customConversions = new CouchbaseCustomConversions(Collections.emptyList());
      this.setCustomConversions(customConversions);
      // if the mappingContext does not have the SimpleTypes, it will not know that they have converters, then it will
      // try to access the fields of the type and (maybe) fail with InaccessibleObjectException
     ((CouchbaseMappingContext)mappingContext).setSimpleTypeHolder(customConversions.getSimpleTypeHolder());
      .
      .

I don't know how a MappingCouchbaseConverter without the CouchbaseCustomConversions was handling any of the Couchbase-specific conversions (seems that it wasn't - whenever it was used in testing, the converters were added, which makes the test somewhat pointless).

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

Successfully merging a pull request may close this issue.

2 participants