Function isAssignableFrom returns false during server startup

ぐ巨炮叔叔 提交于 2020-01-14 14:44:49

问题


Implementing an oauth2 system, I am having some problems with the following code:

import org.springframework.security.oauth2.provider.endpoint.FrameworkEndpointHandlerMapping;
import org.springframework.web.servlet.HandlerMapping;

...
HandlerMapping.class.isAssignableFrom(FrameworkEndpointHandlerMapping.class);

Indeed, as the class FrameworkEndpointHandlerMapping is implementing the interface HandlerMapping, this function should always return true. It is the case when I run a unit test on this function. However, during the startup of the server, this function returns false (checked using the debugger). This is a huge problem because when the DispatcherServlet is instantiated, it searches for the class implementing HandlerMapping and my FrameworkEndpointHandlerMapping is discarded leading to bugs in the application.

I have searched for other questions like this one but most of them answer that the isAssignableFrom method is not used correctly (mix of the class and the parameter of the function). This is not the case here since the JUnit is working.

Suspecting the imported jar files to be the problem, I have limited them to the following ones:

  • spring-beans-4.1.4.RELEASE.jar
  • spring-security-oauth2-2.0.6.RELEASE.jar
  • spring-webmvc-4.1.4.RELEASE.jar (also tried with the 4.0.9)
  • spring-core-4.1.4.RELEASE.jar
  • ...

Do you have any idea of a solution to explore please?

For more information, here are the sources:

My own DispatcherServlet (the constructor with the String as a parameter is called by the JUnit test and the default constructor is called during the startup of the system)

import org.junit.Assert;
import org.springframework.security.oauth2.provider.endpoint.FrameworkEndpointHandlerMapping;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

public class MobileDispatcherServlet extends DispatcherServlet
{

    private static final long serialVersionUID = 1L;

    public MobileDispatcherServlet()
    {
        super();
        HandlerMapping.class.isAssignableFrom(FrameworkEndpointHandlerMapping.class);
    }

    public MobileDispatcherServlet(final WebApplicationContext webApplicationContext)
    {
        super(webApplicationContext);
        final FrameworkEndpointHandlerMapping handlerMapping = webApplicationContext.getBean(FrameworkEndpointHandlerMapping.class);

        HandlerMapping.class.isAssignableFrom(handlerMapping.getClass());
    }

    public MobileDispatcherServlet(final String test)
    {
        Assert.assertTrue(HandlerMapping.class.isAssignableFrom(FrameworkEndpointHandlerMapping.class));
    }
}

The oauth configuration file:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:security="http://www.springframework.org/schema/security"
    xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
                        http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd">

    <!-- Root of the configuration -->
    <!-- The FrameworkEndpointHandlerMapping is created here -->
    <oauth:authorization-server client-details-service-ref="clientDetails"
                                token-services-ref="tokenServices"
                                user-approval-handler-ref="userApprovalHandler"
                                authorization-endpoint-url="/oauth/authorize.action"
                                token-endpoint-url="/oauth/token.action" >
        <oauth:authorization-code authorization-code-services-ref="authorizationCodeServices" disabled="false" />
        <oauth:refresh-token />
    </oauth:authorization-server>

    ...

</beans>

The web.xml:

<web-app id="sitestorefront" version="3.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app.xsd"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app.xsd" 
         metadata-complete="true">

...

    <context-param>
        <description>
            The 'contextConfigLocation' param specifies where your configuration files are located.
            The 'WEB-INF/config/web-application-config.xml' file includes several other XML config
            files to build up the configuration for the application.
        </description>
        <param-name>contextConfigLocation</param-name>
        <param-value>WEB-INF/config/web-application-config.xml</param-value>
    </context-param>
    <context-param>
        <param-name>tagpoolMaxSize</param-name>
        <param-value>50</param-value>
    </context-param>

<servlet>
        <description>
            DispatcherServlet
        </description>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>be.sbh.site.storefront.oauth2.MobileDispatcherServlet</servlet-class>
        <init-param>
            <description>
                Specifies the location for Spring MVC to load an additional XML configuration file.
                Because hybris is already configured with the XML spring configuration files to load
                we must set this param value to EMPTY in order to prevent loading of the default
                /WEB-INF/applicationContext.xml file.
            </description>
            <param-name>contextConfigLocation</param-name>
            <param-value></param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <!-- Map all requests to the DispatcherServlet -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

...

</web-app>

The web-application-config.xml imports all the configuration files (among them, the oauth configuration file). One of them has a <mvc:annotation-driven /> to enable the mvc annotations.

I tried to limit my sources to the ones that seems relevant to me. If you need more, do not hesitate to ask me.

Thank you for reading this question,

Laurent


回答1:


This is really weird. Facing such a problem, I would first suspect that the bean is not found, or is hidden by a bean of same name in a child application context. But as you say you managed to see that ClassUtils.isAssignableFrom was called and returned False, I admit the correct bean was found and tested.

The last problem I can imagine would be multiple instances of HandlerMapping in classpath. As suggested by JonSkeet's comment, if you have multiple spring-webmvc.jar in classpath, the classloader for FrameworkEndpointHandlerMapping could have pick one, and the classloader for your custom DispatcherServlet could have pick another one.

If you are using maven, do control the dependency graph. And anyway, do control the list of jars in lib folder of you app and of the servlet container, and the ones publically accessible through a global CLASSPATH environment variable



来源:https://stackoverflow.com/questions/30195166/function-isassignablefrom-returns-false-during-server-startup

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!