`
yixietianxia
  • 浏览: 14081 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Swagger与Disconf包冲突解决之道

阅读更多

      这周写的文档实在太多,都没时间看看技术的东西。前几天把Swagger跟Dubbox结合完成后,心想可以在项目中推广使用了。然而,事情有点出乎意料!当我拿着第一个项目做试点的时候,发现实际项目中Disconf的org.reflections依赖包跟Swagger的org.reflections版本冲突!Disconf依赖它的版本是0.9.9-RC1,Swagger(1.5.8)依赖它的版本是0.9.10。如果强制采用0.9.10的版本,系统都无法启动。为了维持现有系统的稳定,我只好把Swagger依赖的版本降低。

 

       然而Swagger对这块的兼容也比较差,降低版本后系统启动也会失败,一直提示:Property 'scan' threw exception; nested exception is java.lang.NoSuchMethodError:org.reflections.util.ClasspathHelper.forPackage(Ljava/lang/String;[Ljava/lang/ClassLoader;)Ljava/util/Collection。在社区上找了一圈也没有提供什么解决方案。没办法只好自己啃骨头了。

 

       要解决这个问题,如果一直瞄准它这个提示信息,你永远也找不到方案,提示说这个类没有这个方法,但是实际上又存在。开启调试,跟进代码发现其实在调用ClasspathHelper.forPackage时,这个类是一个抽象类,spring在初始化bean的时候根本没法创建其实例对象。问题根源找到了我们在说解决方案。

 

       具体解决方案如下

       第一、把BeanConfig的scan属性删除,新增一个init方法,在初始化bean时配置一个init-method属性。代码如下:

 

/**删除这些代码*/
//    public boolean getScan() {
//        return true;
//    }
//
//    public void setScan(boolean shouldScan) {
//        scanAndRead();
//        new SwaggerContextService()
//                .withConfigId(configId)
//                .withScannerId(scannerId)
//                .withContextId(contextId)
//                .withServletConfig(servletConfig)
//                .withSwaggerConfig(this)
//                .withScanner(this)
//                .initConfig()
//                .initScanner();
//    }
//
//    public void setScan() {
//        setScan(true);
//    }

/**新增该方法:*/
    public void init() {
        scanAndRead();
        new SwaggerContextService()
                .withConfigId(configId)
                .withScannerId(scannerId)
                .withContextId(contextId)
                .withServletConfig(servletConfig)
                .withSwaggerConfig(this)
                .withScanner(this)
                .initConfig()
                .initScanner();
    }

 

         第二步、把org.reflections包ClasspathHelper类代码拷贝新创一个普通类

  

package io.swagger.jaxrs.config;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

import javax.servlet.ServletContext;

import org.reflections.Reflections;

import com.google.common.collect.Sets;

public class MyReflections{

    /** returns {@code Thread.currentThread().getContextClassLoader()} */
    public static ClassLoader contextClassLoader() { return Thread.currentThread().getContextClassLoader(); }

    /** returns {@code Reflections.class.getClassLoader()} */
    public static ClassLoader staticClassLoader() { return Reflections.class.getClassLoader(); }

    /** returns given classLoaders, if not null, otherwise defaults to both {@link #contextClassLoader()} and {@link #staticClassLoader()} */
    public ClassLoader[] classLoaders(ClassLoader... classLoaders) {
        if (classLoaders != null && classLoaders.length != 0) {
            return classLoaders;
        } else {
            ClassLoader contextClassLoader = contextClassLoader(), staticClassLoader = staticClassLoader();
            return contextClassLoader != null ?
                    staticClassLoader != null && contextClassLoader != staticClassLoader ?
                            new ClassLoader[]{contextClassLoader, staticClassLoader} :
                            new ClassLoader[]{contextClassLoader} :
                    new ClassLoader[] {};

        }
    }

    /** returns urls with resources of package starting with given name, using {@link ClassLoader#getResources(String)}
     * <p>that is, forPackage("org.reflections") effectively returns urls from classpath with packages starting with {@code org.reflections}
     * <p>if optional {@link ClassLoader}s are not specified, then both {@link #contextClassLoader()} and {@link #staticClassLoader()} are used for {@link ClassLoader#getResources(String)}
     */
    public Set<URL> forPackage(String name, ClassLoader... classLoaders) {
        return forResource(resourceName(name), classLoaders);
    }

    /** returns urls with resources of given @{code resourceName}, using {@link ClassLoader#getResources(String)} */
    public Set<URL> forResource(String resourceName, ClassLoader... classLoaders) {
        final Set<URL> result = Sets.newHashSet();
        final ClassLoader[] loaders = classLoaders(classLoaders);
        for (ClassLoader classLoader : loaders) {
            try {
                final Enumeration<URL> urls = classLoader.getResources(resourceName);
                while (urls.hasMoreElements()) {
                    final URL url = urls.nextElement();
                    int index = url.toExternalForm().lastIndexOf(resourceName);
                    if (index != -1) {
                        result.add(new URL(url.toExternalForm().substring(0, index)));
                    } else {
                        result.add(url); //whatever
                    }
                }
            } catch (IOException e) {
                if (Reflections.log != null) {
                    Reflections.log.error("error getting resources for " + resourceName, e);
                }
            }
        }
        return result;
    }

    /** returns the url that contains the given class, using {@link ClassLoader#getResource(String)}
     * <p>if optional {@link ClassLoader}s are not specified, then either {@link #contextClassLoader()} or {@link #staticClassLoader()} are used for {@link ClassLoader#getResources(String)}
     * */
    public URL forClass(Class<?> aClass, ClassLoader... classLoaders) {
        final ClassLoader[] loaders = classLoaders(classLoaders);
        final String resourceName = aClass.getName().replace(".", "/") + ".class";

        for (ClassLoader classLoader : loaders) {
            try {
                final URL url = classLoader.getResource(resourceName);
                if (url != null) {
                    final String normalizedUrl = url.toExternalForm().substring(0, url.toExternalForm().lastIndexOf(aClass.getPackage().getName().replace(".", "/")));
                    return new URL(normalizedUrl);
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
        }

        return null;
    }
    
    /** returns urls using {@link java.net.URLClassLoader#getURLs()} up the default classloaders parent hierarchy
     * <p>using {@link #classLoaders(ClassLoader...)} to get default classloaders
     **/
    public Set<URL> forClassLoader() {
        return forClassLoader(classLoaders());
    }

    /** returns urls using {@link java.net.URLClassLoader#getURLs()} up the classloader parent hierarchy
     * <p>if optional {@link ClassLoader}s are not specified, then both {@link #contextClassLoader()} and {@link #staticClassLoader()} are used for {@link ClassLoader#getResources(String)}
     * */
    public Set<URL> forClassLoader(ClassLoader... classLoaders) {
        final Set<URL> result = Sets.newHashSet();

        final ClassLoader[] loaders = classLoaders(classLoaders);

        for (ClassLoader classLoader : loaders) {
            while (classLoader != null) {
                if (classLoader instanceof URLClassLoader) {
                    URL[] urls = ((URLClassLoader) classLoader).getURLs();
                    if (urls != null) {
                        result.addAll(Sets.<URL>newHashSet(urls));
                    }
                }
                classLoader = classLoader.getParent();
            }
        }

        return result;
    }

    /** returns urls using {@code java.class.path} system property */
    public Set<URL> forJavaClassPath() {
        Set<URL> urls = Sets.newHashSet();

        String javaClassPath = System.getProperty("java.class.path");
        if (javaClassPath != null) {
            for (String path : javaClassPath.split(File.pathSeparator)) {
                try { urls.add(new File(path).toURI().toURL()); }
                catch (Exception e) { e.printStackTrace(); }
            }
        }

        return urls;
    }

    /** returns urls using {@link ServletContext} in resource path WEB-INF/lib */
    public Set<URL> forWebInfLib(final ServletContext servletContext) {
        final Set<URL> urls = Sets.newHashSet();

        for (Object urlString : servletContext.getResourcePaths("/WEB-INF/lib")) {
            try { urls.add(servletContext.getResource((String) urlString)); }
            catch (MalformedURLException e) { /*fuck off*/ }
        }

        return urls;
    }

    /** returns url using {@link ServletContext} in resource path WEB-INF/classes */
    public URL forWebInfClasses(final ServletContext servletContext) {
        try {
            final String path = servletContext.getRealPath("/WEB-INF/classes");
            if (path != null) {
                final File file = new File(path);
                if (file.exists())
                    return file.toURL();
            } else {
                return servletContext.getResource("/WEB-INF/classes");
            }
        }
        catch (MalformedURLException e) { /*fuck off*/ }

        return null;
    }

    /** return urls that are in the current class path.
     * attempts to load the jar manifest, if any, and adds to the result any dependencies it finds. */
    public Set<URL> forManifest() {
        return forManifest(forClassLoader());
    }

    /** get the urls that are specified in the manifest of the given url for a jar file.
     * attempts to load the jar manifest, if any, and adds to the result any dependencies it finds. */
    public Set<URL> forManifest(final URL url) {
        final Set<URL> result = Sets.newHashSet();

        result.add(url);

        try {
            final String part = cleanPath(url);
            File jarFile = new File(part);
            JarFile myJar = new JarFile(part);

            URL validUrl = tryToGetValidUrl(jarFile.getPath(), new File(part).getParent(), part);
            if (validUrl != null) { result.add(validUrl); }

            final Manifest manifest = myJar.getManifest();
            if (manifest != null) {
                final String classPath = manifest.getMainAttributes().getValue(new Attributes.Name("Class-Path"));
                if (classPath != null) {
                    for (String jar : classPath.split(" ")) {
                        validUrl = tryToGetValidUrl(jarFile.getPath(), new File(part).getParent(), jar);
                        if (validUrl != null) { result.add(validUrl); }
                    }
                }
            }
        } catch (IOException e) {
            // don't do anything, we're going on the assumption it is a jar, which could be wrong
        }

        return result;
    }

    /** get the urls that are specified in the manifest of the given urls.
     * attempts to load the jar manifest, if any, and adds to the result any dependencies it finds. */
    public Set<URL> forManifest(final Iterable<URL> urls) {
        Set<URL> result = Sets.newHashSet();

        // determine if any of the URLs are JARs, and get any dependencies
        for (URL url : urls) {
            result.addAll(forManifest(url));
        }

        return result;
    }

    //
    //a little bit cryptic...
    URL tryToGetValidUrl(String workingDir, String path, String filename) {
        try {
            if (new File(filename).exists())
                return new File(filename).toURI().toURL();
            if (new File(path + File.separator + filename).exists())
                return new File(path + File.separator + filename).toURI().toURL();
            if (new File(workingDir + File.separator + filename).exists())
                return new File(workingDir + File.separator + filename).toURI().toURL();
            if (new File(new URL(filename).getFile()).exists())
                return new File(new URL(filename).getFile()).toURI().toURL();
        } catch (MalformedURLException e) {
            // don't do anything, we're going on the assumption it is a jar, which could be wrong
        }
        return null;
    }

    public String cleanPath(final URL url) {
        String path = url.getPath();
        try {
            path = URLDecoder.decode(path, "UTF-8");
        } catch (UnsupportedEncodingException e) { /**/ }
        if (path.startsWith("jar:")) {
            path = path.substring("jar:".length());
        }
        if (path.startsWith("file:")) {
            path = path.substring("file:".length());
        }
        if (path.endsWith("!/")) {
            path = path.substring(0, path.lastIndexOf("!/")) + "/";
        }
        return path;
    }

    private String resourceName(String name) {
        if (name != null) {
            String resourceName = name.replace(".", "/");
            resourceName = resourceName.replace("\\", "/");
            if (resourceName.startsWith("/")) {
                resourceName = resourceName.substring(1);
            }
            return resourceName;
        } else {
            return name;
        }
    }
}

       第三步、把swagger的BeanConfig类中的classes()方法里的代码替换一下

                    //config.addUrls(ClasspathHelper.forPackage(pkg));
                    
                    MyReflections ref =new MyReflections();
                    config.addUrls(ref.forPackage(pkg));

       这样打包上传私库。

 

       处理完成后,再拿试点项目测试,一切都正常了!终于有丢掉了一件事情,下周正式推广!

      

 

分享到:
评论

相关推荐

    swagger所有相关jar包

    这个库包含多个模块,如`springfox-swagger2`用于处理Swagger 2.0规范,`springfox-swagger-ui`则提供了与Swagger UI集成的设施,让开发者在本地就能查看和测试API。 使用Swagger和Springfox,开发者可以实现以下...

    swagger2依赖包

    这个“swagger2依赖包”包含了Swagger2实现所需的关键组件,使得开发人员可以自动化生成API的客户端代码,从而简化了与服务端交互的过程。 Swagger-Annotations-1.5.9是Swagger的核心组件之一,它提供了Java注解,...

    swagger所需jar包大全

    在Spring MVC框架中,Swagger可以与之完美结合,帮助开发人员更轻松地管理API接口。这个"swagger所需jar包大全"包含了使用Swagger进行API文档构建和接口调试所需要的所有关键库。 首先,我们来看`lib`目录下的jar包...

    Swagger搜索源码包

    在这个"Swagger搜索源码包"中,我们重点探讨的是Swagger新版本3.0(OpenAPI 3.0.0)关于搜索功能的实现和源码解析。 OpenAPI规范(OAS)是Swagger的核心,它是定义RESTful API接口的标准。OpenAPI 3.0.0是该规范的...

    swagger静态部分文件打包

    以下是一些与 Swagger 静态部分相关的知识点: 1. **OpenAPI 规范**:Swagger 基于 OpenAPI 规范,这是一种标准的、语言无关的格式,用于描述 RESTful API。它定义了如何编写 API 文档,包括端点、方法、参数、响应...

    整合案例springboot整合swagger+mybatis-plus

    Swagger通过使用Swagger-UI和Swagger-Annotations,可以让开发者以注解的方式描述API,然后自动生成易于理解和使用的Web服务接口文档。这样,开发人员和测试人员可以方便地查看和测试API,无需手动编写文档。 首先...

    springboot整合swagger-bootstrap-ui,过滤器放开并解决自定义错误信息返回冲突-DEMO

    springboot整合swagger-bootstrap-ui,过滤器放开并解决自定义错误信息返回冲突-DEMO

    Swagger与SpringMVC项目整合jar包

    在与SpringMVC框架整合时,Swagger可以提供一个交互式的文档界面,使得开发者可以通过UI直接测试API,大大提升了开发效率和用户体验。下面将详细介绍Swagger与SpringMVC整合的相关知识点。 1. **Swagger介绍** ...

    swagger2.zip

    -- 解决进入swagger页面报类型转换错误,排除2.9.2中的引用,手动增加1.5.21以上版本,这里选1.6.0版本--&gt; &lt;groupId&gt;io.swagger &lt;artifactId&gt;swagger-annotations &lt;version&gt;1.6.0 &lt;!-- ...

    springmvc整合swagger所需jar包

    因此,在集成过程中,首先要明确当前Spring项目的Spring MVC版本,并找到与之兼容的Swagger版本。 Swagger的核心组件主要包括以下jar包: 1. `swagger-core`:提供了核心的API定义和解析功能。 2. `swagger-ui`:...

    springmvc与swagger整合使用的包 普通web项目的jar工程包

    在IT行业中,SpringMVC和Swagger的整合是一个常见的需求,特别是在构建RESTful API服务时,为了提供清晰的接口文档和方便的API测试。SpringMVC是Spring框架的一部分,用于处理HTTP请求,而Swagger则是一个强大的工具...

    swaggerUI静态资源包

    Spring的灵活性使得与Swagger的集成变得简单,可以无缝地与Spring MVC或Spring Boot结合。 在提供的压缩包文件中,"swagger"很可能是包含Swagger UI静态资源的文件夹。这些资源包括HTML、CSS、JavaScript等,用于...

    解决环信导入源码后io.swagger的导入报错

    本篇文章将详细讲解如何解决“环信导入源码后io.swagger的导入报错”的问题。 首先,我们需要了解环信(Easemob)的基本概念。环信是一家提供即时通讯云服务的公司,为开发者提供了丰富的SDK,包括Android、iOS、...

    spring3集成swagger的jar包

    在本例中,"spring3集成swagger的jar包"很可能包含了`swagger-core`、`swagger-springmvc`以及它们的依赖项。你可以通过Maven或Gradle来管理这些依赖,但如果你没有使用构建工具,手动下载jar包也是可行的。 集成...

    SpringMVC中Swagger对应的JAR包

    Swagger与SpringMVC的结合,可以帮助开发者高效地实现RESTful API的设计、测试和文档。 Swagger的核心是OpenAPI Specification(OAS),这是一个用于描述RESTful API的标准,它允许开发者用YAML或JSON格式定义API的...

    swagger ui 汉化资源包

    springmvc和swagger集成之后,自动生成,java服务端api的文档,swagger官网生成的是英文,swagger汉化包,可以为研发人员提供中文界面的文档,让不喜欢英语的同学,看的更直白。

    swagger,基于swagger的前端UI实现

    现在市面上的swagger UI不足之处 1、原生UI显示的有些不够漂亮和清晰,特别是request 的model部分 2、每个服务都需要引入一套资源文件,不能作为一个中间件为其他API使用 3、默认通用配置繁琐,每个项目都需要复制...

    swagger @ApiModel 返回内容注释不显示问题

    Swagger是流行的一款用于构建RESTful API的文档工具,它与SpringBoot结合使用可以方便地在开发过程中实时展示接口文档,帮助开发者理解和测试API。 `@ApiModel`是Swagger的核心注解之一,用于描述一个模型(Model)...

    解决环信io.swagger.client.ApiException包报错

    解决环信io.swagger.client.ApiException包报错以及环信默认包导入工程后的报错问题

    swagger2Demo,swagger

    在这个项目中,开发者使用Java语言(JDK 1.8)实现了Swagger 2的功能,这表明Swagger不仅支持最新的Java版本,而且与旧版本兼容。 Swagger 2的主要特点包括: 1. **API定义**:通过在代码中添加注解,Swagger 2...

Global site tag (gtag.js) - Google Analytics