Spring 4.2.1 on GAE and java.util.ResourceBundle$C

2019-08-13 01:26发布

问题:

If I move from Spring 4.1.7.RELEASE to 4.2.1.RELEASE Google App Engine raises java.lang.NoClassDefFoundError

when Spring Security throws AccessDeniedException (AffirmativeBased.java:83)

I know I do not have access to requested resource. I expect spring to show login page after that but since Spring 4.2 it does not work :(

[INFO] java.lang.NoClassDefFoundError: java.util.ResourceBundle$Control is a restricted class. Please see the Google  App Engine developer's guide for more details.
[INFO]  at com.google.appengine.tools.development.agent.runtime.Runtime.reject(Runtime.java:52)
[INFO]  at org.springframework.context.support.ResourceBundleMessageSource$MessageSourceControl.<init>(ResourceBundleMessageSource.java:417)
[INFO]  at org.springframework.context.support.ResourceBundleMessageSource$MessageSourceControl.<init>(ResourceBundleMessageSource.java:417)
[INFO]  at org.springframework.context.support.ResourceBundleMessageSource.doGetBundle(ResourceBundleMessageSource.java:314)
[INFO]  at org.springframework.context.support.ResourceBundleMessageSource.getResourceBundle(ResourceBundleMessageSource.java:284)
[INFO]  at org.springframework.context.support.ResourceBundleMessageSource.resolveCodeWithoutArguments(ResourceBundleMessageSource.java:234)
[INFO]  at org.springframework.context.support.AbstractMessageSource.getMessageInternal(AbstractMessageSource.java:218)
[INFO]  at org.springframework.context.support.AbstractMessageSource.getMessage(AbstractMessageSource.java:136)
[INFO]  at org.springframework.context.support.MessageSourceAccessor.getMessage(MessageSourceAccessor.java:83)
[INFO]  at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83)
[INFO]  at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:232)
[INFO]  at org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor.invoke(AspectJMethodSecurityInterceptor.java:43)
[INFO]  at org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect.ajc$around$org_springframework_security_access_intercept_aspectj_aspect_AnnotationSecurityAspect$1$c4d57a2b(AnnotationSecurityAspect.aj:63)
[INFO]  at xx.xxx.controllers.PortalController.home(PortalController.java:51)

回答1:

To run Spring 4.2.1 on GAE and use global method security I had to set message source to StaticMessageSource instead of ResourceBundleMessageSource which caused the problem. Unfortunately declaring the messageSource bean is not only one thing that has to be done.

@Bean(name = "messageSource")
  public MessageSource messageSource() {
    StaticMessageSource messageSource = new StaticMessageSource();
    return messageSource;
  }

AffirmativeBased access decision manager which is used here is created by method GlobalMethodSecurityConfiguration.accessDecisionManager() and is not a Spring bean so setMessageSource() method is not executed so it is not MessageSourceAware. The solution for that is to set this messageSource manually:

@Configuration
@EnableGlobalMethodSecurity
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {

  @Inject
  private MessageSource messageSource;

  @Override
  protected AccessDecisionManager accessDecisionManager() {
    AffirmativeBased manager = (AffirmativeBased)super.accessDecisionManager();
    manager.setMessageSource(messageSource);
    return manager;
  }
}


回答2:

After a bit of trial and error, the following seemed to work OK for me:

  1. Move messages files to WEB-INF.
  2. Update Spring config to use ReloadableResourceBundleMessageSource instead of ResourceBundleMessageSource, e.g. in XML

    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basename" value="/WEB-INF/i18n/messages" /> </bean>