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

JPMS: export to spring.core required #33373

Closed
xenoterracide opened this issue Aug 12, 2024 · 4 comments
Closed

JPMS: export to spring.core required #33373

xenoterracide opened this issue Aug 12, 2024 · 4 comments
Labels
in: core Issues in core modules (aop, beans, core, context, expression) status: duplicate A duplicate of another issue

Comments

@xenoterracide
Copy link

xenoterracide commented Aug 12, 2024

This is hopefully just a lack of understanding on how spring "cglib" support is supposed to work (in quotes because it's not cglib anymore right?) or how exactly a reflective access needs exports instead of just opens. Sorry if this isn't simply an understanding problem vs an issue which could be fixed to allow my module to work without adding an exports ... to spring...

// © Copyright 2024 Caleb Cushing
// SPDX-License-Identifier: AGPL-3.0-or-later

package com.xenoterracide.jpa.transaction;

import com.xenoterracide.jpa.annotation.TransactionScope;
import com.xenoterracide.jpa.util.Constants;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import org.jspecify.annotations.NonNull;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.support.SimpleTransactionScope;

/**
 * The type Transaction bean post processor.
 */
@Configuration
class TransactionBeanPostProcessor implements BeanFactoryPostProcessor {

  private static final ZoneId UTC = ZoneId.of("UTC");

  @Bean
  @TransactionScope
  Instant instantNow() {
    return Instant.now();
  }

  @Bean
  @TransactionScope
  ZonedDateTime zonedDateTimeNow(@NonNull Instant instantNow) {
    return instantNow.atZone(UTC);
  }

  /**
   * Offset date time now offset date time.
   *
   * @param zonedDateTimeNow the zoned date time now
   * @return the offset date time
   */
  @Bean
  @TransactionScope
  OffsetDateTime offsetDateTimeNow(@NonNull ZonedDateTime zonedDateTimeNow) {
    return zonedDateTimeNow.toOffsetDateTime();
  }

  @Override
  public void postProcessBeanFactory(@NonNull ConfigurableListableBeanFactory beanFactory) throws BeansException {
    beanFactory.registerScope(Constants.TRANSACTION_SCOPE, new SimpleTransactionScope());
  }
}
import org.jspecify.annotations.NullMarked;

/**
 * JPA utilities.
 */
@NullMarked module com.xenoterracide.jpa {
  exports com.xenoterracide.jpa;
  exports com.xenoterracide.jpa.annotation;
  exports com.xenoterracide.jpa.util;
  opens com.xenoterracide.jpa to org.hibernate.orm.core, spring.core;
  opens com.xenoterracide.jpa.transaction to spring.core;

  requires java.base;
  requires org.apache.commons.lang3;
  requires spring.data.commons;
  requires spring.beans;
  requires spring.context;
  requires spring.tx;
  requires org.hibernate.orm.envers;

  requires static transitive org.jspecify;
  requires static com.xenoterracide.tools.java;
  requires static jakarta.annotation;
  requires transitive jakarta.persistence;
  requires transitive jakarta.validation;
  requires transitive com.xenoterracide.model;
}

Adding this fixes it.

  exports com.xenoterracide.jpa.transaction to spring.beans, spring.context;
    Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.xenoterracide.jpa.transaction.TransactionBeanPostProcessor$$SpringCGLIB$$0]: Is the constructor accessible?

    	at [email protected]/org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335) ~[spring-beans-6.1.11.jar:?]
    	at [email protected]/org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:205) ~[spring-beans-6.1.11.jar:?]
    	at [email protected]/org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:202) ~[spring-context-6.1.11.jar:?]
    	at [email protected]/org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:789) ~[spring-context-6.1.11.jar:?]
    	at [email protected]/org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:607) ~[spring-context-6.1.11.jar:?]
    	at [email protected]/org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-3.3.2.jar:?]
    	at [email protected]/org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[spring-boot-3.3.2.jar:?]
    	at [email protected]/org.springframework.boot.SpringApplication.run(SpringApplication.java:335) ~[spring-boot-3.3.2.jar:?]
    	at [email protected]/org.springframework.boot.test.context.SpringBootContextLoader.lambda$loadContext$3(SpringBootContextLoader.java:137) ~[spring-boot-test-3.3.2.jar:?]
    	at [email protected]/org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:58) ~[spring-core-6.1.11.jar:?]
    	at [email protected]/org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:46) ~[spring-core-6.1.11.jar:?]
    	at [email protected]/org.springframework.boot.SpringApplication.withHook(SpringApplication.java:1463) ~[spring-boot-3.3.2.jar:?]
    	at [email protected]/org.springframework.boot.test.context.SpringBootContextLoader$ContextLoaderHook.run(SpringBootContextLoader.java:553) ~[spring-boot-test-3.3.2.jar:?]
    	at [email protected]/org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:137) ~[spring-boot-test-3.3.2.jar:?]
    	at [email protected]/org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:108) ~[spring-boot-test-3.3.2.jar:?]
    	at [email protected]/org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:225) ~[spring-test-6.1.11.jar:?]
    	at [email protected]/org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:152) ~[spring-test-6.1.11.jar:?]
    	... 130 more
    Caused by: java.lang.IllegalAccessException: class org.springframework.beans.BeanUtils (in module spring.beans) cannot access class com.xenoterracide.jpa.transaction.TransactionBeanPostProcessor$$SpringCGLIB$$0 (in module com.xenoterracide.jpa) because module com.xenoterracide.jpa does not export com.xenoterracide.jpa.transaction to module spring.beans

    Caused by: java.lang.IllegalAccessException: class org.springframework.beans.BeanUtils (in module spring.beans) cannot access class com.xenoterracide.jpa.transaction.TransactionBeanPostProcessor$$SpringCGLIB$$0 (in module com.xenoterracide.jpa) because module com.xenoterracide.jpa does not export com.xenoterracide.jpa.transaction to module spring.beans
    	at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:394) ~[?:?]
    	at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:714) ~[?:?]
    	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:495) ~[?:?]
    	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:486) ~[?:?]
    	at [email protected]/org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:195) ~[spring-beans-6.1.11.jar:?]
    	at [email protected]/org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:94) ~[spring-beans-6.1.11.jar:?]
    	at [email protected]/org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1331) ~[spring-beans-6.1.11.jar:?]
    	at [email protected]/org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1222) ~[spring-beans-6.1.11.jar:?]
    	at [email protected]/org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:562) ~[spring-beans-6.1.11.jar:?]
    	at [email protected]/org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) ~[spring-beans-6.1.11.jar:?]
    	at [email protected]/org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337) ~[spring-beans-6.1.11.jar:?]
    	at [email protected]/org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.1.11.jar:?]
    	at [email protected]/org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335) ~[spring-beans-6.1.11.jar:?]
    	at [email protected]/org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:205) ~[spring-beans-6.1.11.jar:?]
    	at [email protected]/org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:202) ~[spring-context-6.1.11.jar:?]
    	at [email protected]/org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:789) ~[spring-context-6.
    1.11.jar:?]
    	at [email protected]/org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:607) ~[spring-context-6.1.11.jar:?]
    	at [email protected]/org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-3.3.2.jar:?]
    	at [email protected]/org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[spring-boot-3.3.2.jar:?]
    	at [email protected]/org.springframework.boot.SpringApplication.run(SpringApplication.java:335) ~[spring-boot-3.3.2.jar:?]
    	at [email protected]/org.springframework.boot.test.context.SpringBootContextLoader.lambda$loadContext$3(SpringBootContextLoader.java:137) ~[spring-boot-test-3.3.2.jar:?]
    	at [email protected]/org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:58) ~[spring-core-6.1.11.jar:?]
    	at [email protected]/org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:46) ~[spring-core-6.1.11.jar:?]
    	at [email protected]/org.springframework.boot.SpringApplication.withHook(SpringApplication.java:1463) ~[spring-boot-3.3.2.jar:?]
    	at [email protected]/org.springframework.boot.test.context.SpringBootContextLoader$ContextLoaderHook.run(SpringBootContextLoader.java:553) ~[spring-boot-test-3.3.2.jar:?]
    	at [email protected]/org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:137) ~[spring-boot-test-3.3.2.jar:?]
    	at [email protected]/org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:108) ~[spring-boot-test-3.3.2.jar:?]
    	at [email protected]/org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:225) ~[spring-test-6.1.11.jar:?]
    	at [email protected]/org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:152) ~[spring-test-6.1.11.jar:?]
    	... 130 more
 Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionBeanPostProcessor' defined in URL [jar:file:///home/xeno/IdeaProjects/spring-app-commons/module/jpa/build/libs/jpa.jar!/com/xenoterracide/jpa/transaction/TransactionBeanPostProcessor.class]: class org.springframework.context.annotation.ConfigurationClassEnhancer$BeanFactoryAwareMethodInterceptor (in module spring.context) cannot access class com.xenoterracide.jpa.transaction.TransactionBeanPostProcessor$$SpringCGLIB$$0 (in module com.xenoterracide.jpa) because module com.xenoterracide.jpa does not export com.xenoterracide.jpa.transaction to module spring.context

    	at [email protected]/org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:108) ~[spring-boot-test-3.3.2.jar:?]
    	at [email protected]/org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:225) ~[spring-test-6.1.11.jar:?]
    	at [email protected]/org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:152) ~[spring-test-6.1.11.jar:?]
    	... 130 more
    Caused by: java.lang.IllegalAccessException: class org.springframework.context.annotation.ConfigurationClassEnhancer$BeanFactoryAwareMethodInterceptor (in module spring.context) cannot access class com.xenoterracide.jpa.transaction.TransactionBeanPostProcessor$$SpringCGLIB$$0 (in module com.xenoterracide.jpa) because module com.xenoterracide.jpa does not export com.xenoterracide.jpa.transaction to module spring.context
    	at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:394) ~[?:?]

org.springframework:spring-core:6.1.11


------------------------------------------------------------
Gradle 8.9
------------------------------------------------------------

Build time:    2024-07-11 14:37:41 UTC
Revision:      d536ef36a19186ccc596d8817123e5445f30fef8

Kotlin:        1.9.23
Groovy:        3.0.21
Ant:           Apache Ant(TM) version 1.10.13 compiled on January 4 2023
Launcher JVM:  21.0.4 (Eclipse Adoptium 21.0.4+7-LTS)
Daemon JVM:    /home/xeno/.asdf/installs/java/temurin-21.0.4+7.0.LTS (no JDK specified, using current Java home)
OS:            Linux 6.6.41-1-MANJARO amd64

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Aug 12, 2024
@xenoterracide xenoterracide changed the title JPMS: export to spring.core require JPMS: export to spring.core required Aug 12, 2024
@jhoeller jhoeller added the in: core Issues in core modules (aop, beans, core, context, expression) label Aug 20, 2024
@sdeleuze sdeleuze added status: waiting-for-internal-feedback An issue that needs input from a member or another Spring Team and removed status: waiting-for-internal-feedback An issue that needs input from a member or another Spring Team labels Sep 5, 2024
@sbrannen
Copy link
Member

Hi @xenoterracide,

For starters, it's still CGLIB just rather our port of CGLIB which we now maintain.

Regarding the exception you've encountered, ConfigurationClassEnhancer$BeanFactoryAwareMethodInterceptor likely signals that there was an issue related to a dynamic subclass of your @Configuration class.

To avoid that, try @Configuration(proxyBeanMethods = false) and let us know if that solves your problem.

As a side note, we don't recommend that a @Configuration class implement BeanFactoryPostProcessor. Instead, a @Configuration class should contain a static @Bean method that returns an instance of your BeanFactoryPostProcessor.

@xenoterracide
Copy link
Author

xenoterracide commented Sep 10, 2024

As a side note, we don't recommend that a @configuration class implement BeanFactoryPostProcessor. Instead, a @configuration class should contain a static @bean method that returns an instance of your BeanFactoryPostProcessor.

for some reason I never considered that, or using statics...

For starters, it's still CGLIB just rather our port of CGLIB which we now maintain.

well now I wonder if bytebuddy has the same issue

To avoid that, try @configuration(proxyBeanMethods = false) and let us know if that solves your problem.

It does, although I think I prefer the export because I can solve that in 1 place instead of N, or in theory at least less places (since I have N libraries). I have @SpringBootApplication(proxyBeanMethods = false) so I figured I wouldn't have to do it again. For some, unknown, reason I presumed that would be a default; like the component scanning package is for the whole app by default.

I still don't understand why the export helps here. Might be worth documenting these options.

@xenoterracide
Copy link
Author

well now I wonder if bytebuddy has the same issue

and why I don't seem to have it with hibernate, which I would think has to accomplish something similar with its magic.

@xenoterracide
Copy link
Author

I think this is just a duplicate of #32671 re-open if you disagree

@bclozel bclozel added status: duplicate A duplicate of another issue and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Sep 10, 2024
@bclozel bclozel closed this as not planned Won't fix, can't repro, duplicate, stale Sep 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) status: duplicate A duplicate of another issue
Projects
None yet
Development

No branches or pull requests

6 participants