0

I've an error using Spring when changing the visibility of a variable.

I've this code (which works fine)

@Component
public class TennisCoach implements Coach {

    @Autowired
    public FortuneService fortuneService;

    @Override
    public String getDailyWorkout() {
        return "Do tennis stuff!";
    }

    @Override
    public String getFortune() {
        return fortuneService.getFortune();
    }

}

(FortunateService is an interface, and I've a class HappyFortunateService which implements it, and I've it annotated with @Component as well)

with this main method

public static void main(String[] args) {
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    Coach annotatedCoach = context.getBean("tennisCoach", Coach.class);

    System.out.println(annotatedCoach.getDailyWorkout());
    System.out.println(annotatedCoach.getFortune());

    context.close();

}

And when I turn on the TennisCoach class the fortunateService variable visibility to private, I get this error:

org.springframework.context.support.AbstractApplicationContext refresh
WARNING: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'tennisCoach': Injection of autowired dependencies failed; nested exception is java.lang.reflect.InaccessibleObjectException: Unable to make field private me.davichete.springproject.FortuneService me.davichete.springproject.TennisCoach.fortuneService accessible: module spring_project does not "opens me.davichete.springproject" to module spring.core
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'tennisCoach': Injection of autowired dependencies failed; nested exception is java.lang.reflect.InaccessibleObjectException: Unable to make field private me.davichete.springproject.FortuneService me.davichete.springproject.TennisCoach.fortuneService accessible: module spring_project does not "opens me.davichete.springproject" to module spring.core
    at spring.beans@5.2.9.RELEASE/org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:405)
    at spring.beans@5.2.9.RELEASE/org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420)
    at spring.beans@5.2.9.RELEASE/org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593)
    at spring.beans@5.2.9.RELEASE/org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516)
    at spring.beans@5.2.9.RELEASE/org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:324)
    at spring.beans@5.2.9.RELEASE/org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
    at spring.beans@5.2.9.RELEASE/org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)
    at spring.beans@5.2.9.RELEASE/org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
    at spring.beans@5.2.9.RELEASE/org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:897)
    at spring.context@5.2.9.RELEASE/org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:879)
    at spring.context@5.2.9.RELEASE/org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:551)
    at spring.context@5.2.9.RELEASE/org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:144)
    at spring.context@5.2.9.RELEASE/org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:85)
    at spring_project/me.davichete.springproject.HelloSpringApp.main(HelloSpringApp.java:8)
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private me.davichete.springproject.FortuneService me.davichete.springproject.TennisCoach.fortuneService accessible: module spring_project does not "opens me.davichete.springproject" to module spring.core
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:361)
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:301)
    at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:177)
    at java.base/java.lang.reflect.Field.setAccessible(Field.java:171)
    at spring.core@5.2.9.RELEASE/org.springframework.util.ReflectionUtils.makeAccessible(ReflectionUtils.java:782)
    at spring.beans@5.2.9.RELEASE/org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:667)
    at spring.beans@5.2.9.RELEASE/org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:130)
    at spring.beans@5.2.9.RELEASE/org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399)
    ... 13 more

Does anybody know why? Spring version: 5.2.9 Java SE15

EDIT: My project is set up adding the Spring JAR files to the ModulePath, I'm not using Maven.

My module-info.java looks like this:

module spring_project {
    requires spring.context;
    requires java.logging;
    requires spring.beans;

    exports me.davichete.springproject;
}

EDIT: I tested it deleting the module-info.java, and now it seems to work, probably related to the answer of @Menelaos

Davichete
  • 415
  • 7
  • 14

1 Answers1

3

Try adding a constructor and making your field final

If you are using Lambok, you could do the following:

  1. Set @RequiredArgsConstructor on your class - which will generate a constructor with params for all final variables.
  2. Change your field to final, and get rid of @Autowired.

Spring will take care of injecting the value for final fields.

If you are not using lambok, you need to add the constructor by hand.

See the constructor injection example @ https://stackoverflow.com/a/55473346/1688441

Java 9 Modules

Have a look also at the following: How to solve InaccessibleObjectException ("Unable to make {member} accessible: module {A} does not 'opens {package}' to {B}") on Java 9?

Your error is due to limitations and changes in Java 9.

Menelaos
  • 23,508
  • 18
  • 90
  • 155
  • I already had my project exported, but it still does not work :( – Davichete Feb 07 '21 at 23:24
  • Yes, I agree, looks like he created a module which does not export the package where the class is included. – Marco Tizzano Feb 07 '21 at 23:24
  • It's actually recommended to get rid of @Autowired, and switch to constructor injection. See: https://stackoverflow.com/questions/40620000/spring-autowire-on-properties-vs-constructor – Menelaos Feb 07 '21 at 23:26
  • Yes, I know the other way is more idiomatic, but I just have the doubt about why in my case it won't work but on the documentation it says it is supposed to work, maybe is because I'm not using Maven but rather putting the JARs into the classpath, and I'm maybe missing a configuration that Maven would do for me, but I don't know – Davichete Feb 07 '21 at 23:31
  • This seems to be the reason finally, but the code provided does not solve the issue. If you edit it and delete the module code (or document it further), I'll accept it as the answer :D – Davichete Feb 07 '21 at 23:45
  • 1
    @Davichete Done. Removed the module code. – Menelaos Feb 07 '21 at 23:47
  • 1
    @Menelaos Thank you, btw this sentence was super helpful, I recommend adding it again :D: "Your error is due to limitations and changes in Java 9." – Davichete Feb 07 '21 at 23:50