梦想是指引我们前行的星光,无论夜有多黑,它总能照亮前方|

园龄:粉丝:关注:

jar包的License信息都存在于哪块jar包的License信息都存在于哪块

最近两天在搞产品发布前的jar包License扫描工作,因为这个数据交换项目是基于Kettle做的二次开发,而Kettle本身是一款强大的开源数据交换产品,其中包含了近两千个jar包,所以为了产品发布后不被惹上官司,需要扫描介质里所有jar包的License。

那么问题来了,如何扫描介质里所有jar包的License呢?

大概了解pom.xml文件的小伙伴可能有想法了,直接去<licenses>标签获取即可。

另外,熟悉Maven公共库网站https://mvnrepository.com/的小伙伴可能也有想法了,可以写段Java程序,拼接url(https:/mvnrepository.com/artifact/groupId/artifactId/version)在线获取jar包信息Html页面,再去解析即可。

那么url标红的变量从哪获取呢?对于绝大部分小伙伴来说,项目开发就在外网,所以直接去遍历扫描Maven仓库目录即可轻松获取到(当然,这种也有局限性,就是这个jar包必须是Maven编译出来的,而非Ant);但是对于像我们这种在公司内网开发的来说,领导最多能帮你把介质放到外网就不错了,所以你拥有的只有jar包本身,要想获取以上三个变量,需要解析pom.xml文件(这种也有同样的局限性),这里建议最好使用Maven官方的API工具类MavenXpp3Reader来准确解析(maven-model-3.6.0.jar),以免自己手动解析xml出现各种问题,特别是需要扫描很多jar包的时候。一个好的Java程序员应该尝试熟悉使用各种外部工具,毕竟Java流行的原因很大程度上得益于Java开源社区的强大支持。实现代码如下:

  1.  
    public static boolean searchInPom(MyFileEntity fe) {
  2.  
    JarFile jf = null;
  3.  
    try {
  4.  
    jf = new JarFile(fe.getFile());
  5.  
    Enumeration<?> entries = jf.entries();
  6.  
    while (entries.hasMoreElements()) {
  7.  
    JarEntry entry = (JarEntry) entries.nextElement();
  8.  
    if (entry.getName().toLowerCase().endsWith("pom.xml")) {
  9.  
    StringWriter writer = new StringWriter();
  10.  
    try {
  11.  
    org.springframework.util.FileCopyUtils.copy(new InputStreamReader(jf.getInputStream(entry)),
  12.  
    writer);
  13.  
    } catch (IOException e1) {
  14.  
    e1.printStackTrace();
  15.  
    }
  16.  
    StringReader sr = new StringReader(writer.toString());
  17.  
    MavenXpp3Reader reader = new MavenXpp3Reader();
  18.  
    Model model = null;
  19.  
    try {
  20.  
    model = reader.read(sr);
  21.  
    List<License> licenses = model.getLicenses();
  22.  
    if (licenses != null && licenses.size() > 0) {
  23.  
    // System.out.println(licenses.get(0).getName());
  24.  
    fe.setLicense(licenses.get(0).getName());
  25.  
    return true;
  26.  
    } else {
  27.  
    // pom中没有license标签,则尝试联网获取
  28.  
    String groupId = model.getGroupId();
  29.  
    String artifactId = model.getArtifactId();
  30.  
    String version = model.getVersion();
  31.  
    Parent parent = model.getParent();
  32.  
    String groupId2 = null;
  33.  
    String artifactId2 = null;
  34.  
    String version2 = null;
  35.  
    if (parent != null) {
  36.  
    groupId2 = parent.getGroupId();
  37.  
    artifactId2 = parent.getArtifactId();
  38.  
    version2 = parent.getVersion();
  39.  
    }
  40.  
    // 自定义的fe对象简单封装了这三个变量groupId,artifactId和version
  41.  
    fe.setGroupId(groupId == null ? groupId2 : groupId);
  42.  
    fe.setArtifactId(artifactId == null ? artifactId2 : artifactId);
  43.  
    fe.setVersion(version == null ? version2 : version);
  44.  
    // System.out.println(fe);
  45.  
    return searchOnInet(fe); // searchOnInet方法自己实现
  46.  
    }
  47.  
    } catch (IOException | XmlPullParserException e) {
  48.  
    e.printStackTrace();
  49.  
    } finally {
  50.  
    if (sr != null) {
  51.  
    sr.close();
  52.  
    }
  53.  
    }
  54.  
    }
  55.  
    }
  56.  
    } catch (IOException e2) {
  57.  
    e2.printStackTrace();
  58.  
    } finally {
  59.  
    try {
  60.  
    if (jf != null) {
  61.  
    jf.close();
  62.  
    }
  63.  
    } catch (IOException e) {
  64.  
    e.printStackTrace();
  65.  
    }
  66.  
    }
  67.  
    return false;
  68.  
    }

其实,jar包的License信息的存放是有千奇百怪的规范或方式,那接下来总结一下哪些相对具体的地方都有可能放置License吧。

一.META-INF/maven/**/pom.xml

具体位置1:Licenses元素

条件:Maven编译出来的jar,且要含有此标签,有的pom中无此标签(如slf4j-api-1.6.1.jar)

示例:mssql-jdbc.jar

具体位置2:一般在pom开头的注释

条件:Maven编译出来的jar,且要含有相关注释,有的pom中无此注释(如slf4j-api-1.6.1.jar)

示例:commons-io.jar

二.META-INF/MANIFEST.MF

具体位置:Bundle-License:***

条件:含有MANIFEST.MF文件,有的无此文件(如jmi.jar),且含有此key,有的无此key(如asm.jar)

示例:mssql-jdbc.jar

补充获取License实现代码(需要准确获取MANIFEST中的License信息,可以使用jdk的类java.util.jar.Manifest):

  1.  
    public static final String MANIFEST_ENTRY = "META-INF/MANIFEST.MF";
  2.  
    static String LICENSE_TAG = "Bundle-License";
  3.  
    public static boolean searchInMf(MyFileEntity fe) {
  4.  
    JarFile jf = null;
  5.  
    FileInputStream fis = null;
  6.  
    try {
  7.  
    jf = new JarFile(fe.getFile());
  8.  
    JarEntry entry = jf.getJarEntry(MANIFEST_ENTRY);
  9.  
    if (entry != null) {
  10.  
    Manifest m = jf.getManifest();
  11.  
    Attributes ma = m.getMainAttributes();
  12.  
    String url = ma.getValue(LICENSE_TAG);
  13.  
    if (url != null) {
  14.  
    // System.out.println(url);
  15.  
    fe.setUrl(url);
  16.  
    return true;
  17.  
    }
  18.  
    }
  19.  
    } catch (IOException e) {
  20.  
    e.printStackTrace();
  21.  
    } finally {
  22.  
    try {
  23.  
    if (fis != null) {
  24.  
    jf.close();
  25.  
    }
  26.  
    } catch (IOException e) {
  27.  
    e.printStackTrace();
  28.  
    }
  29.  
    }
  30.  
    return false;
  31.  
    }

三.META-INF/LICENSE或META-INF/LICENSE.txt(有的在META-INF下,有的不在)

具体位置:一般存在于第一二行文本

条件:META-INF下含有此文件,有的无此文件(如mssql-jdbc.jar),有的有此文件,但打开无License信息(如dom4j.jar)

示例:apache-log4j-extras.jar

四.META-INF/NOTICE或META-INF/NOTICE.txt

具体位置:License文本信息位置不固定

条件:META-INF下含有此文件,有的无此文件(如guava.jar)

示例:fastjson.jar

五.其他

具体位置:about.html或其他各种文件

条件:任何文件都有可能,因为任何文件可以被人为写入任何信息包括license

示例1:jface.jar(about.html)

示例2:ftp4che.jar(COPYING文件)

示例3:ftp4che.jar(类注释)

示例4:bcprov-jdk14.jar(LICENSE.java)

转载于:https://www.cnblogs.com/songzehao/p/10854262.html

本文作者:云龙

本文链接:https://www.cnblogs.com/yunlong-study/p/14737969.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   云long  阅读(642)  评论(0编辑  收藏  举报
(评论功能已被禁用)
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
展开