Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/339.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在尝试创建URL时,Java JDK 8中存在异常_Java_Url_Jar - Fatal编程技术网

在尝试创建URL时,Java JDK 8中存在异常

在尝试创建URL时,Java JDK 8中存在异常,java,url,jar,Java,Url,Jar,在我尝试创建带有嵌套JAR间接寻址的URL时,现在有一个例外 例如,我有以下嵌套jar URL: jar:jar:file:/D://samples/File.zip!/71812_file!/myFile.properties 它是一个带有两个间接地址的嵌套Jar URL 当我尝试执行以下简单行时: URL url = new URL(spec); 我有以下例外: java.net.MalformedURLException: Nested JAR URLs are not support

在我尝试创建带有嵌套JAR间接寻址的URL时,现在有一个例外

例如,我有以下嵌套jar URL:

jar:jar:file:/D://samples/File.zip!/71812_file!/myFile.properties
它是一个带有两个间接地址的嵌套Jar URL

当我尝试执行以下简单行时:

URL url = new URL(spec);
我有以下例外:

java.net.MalformedURLException: Nested JAR URLs are not supported
现在它不再工作了(JDK8_271),但在较旧的JDK8版本中(例如,在我的内存中是92),同样的代码也可以工作

JDK中创建此异常的“违规”代码(以前在JDK代码中不存在)似乎位于sun.net.www.protocol.jar.Handler类中(源代码):


我现在可以做些什么来解决这个问题,新的JDK版本可以吗?

好的,所以这里真正的问题是标准Java类加载器不支持嵌套JAR文件,也从来没有支持过嵌套JAR文件。对此,有一个长期存在的功能请求;请参阅

这同样适用于使用
URL.openConnection()
打开嵌套JAR

所发生的事情是JDK 7(!)及其后版本(2019年6月)发生了更改,因此,当您尝试解析URL时,会出现一个明显的异常

如果无法将嵌套JAR提取到文件中,那么解决方案将是为理解嵌套JAR文件的
JAR:
查找(或写入)并注册第三方URL协议处理程序类

一种可能是JBoss
njar:


现在它不再工作了(JDK8_271),但在较旧的JDK8版本中(例如,在我的内存中是92),同样的代码也可以工作

解析URL可能有效。但是
java.net.URL
类中的注释暗示
URL.openConnection
不适用于嵌套的
JAR
URL

if ("jar".equalsIgnoreCase(protocol)) {
    if (handler instanceof sun.net.www.protocol.jar.Handler) {
        // URL.openConnection() would throw a confusing exception
        // so generate a better exception here instead.
        String s = ((sun.net.www.protocol.jar.Handler) handler).checkNestedProtocol(file);
        if (s != null) {
            throw new MalformedURLException(s);
        }
    }
}

嗯,现在我明白了!事实上我已经创建了自己的URLConnection,因为我没有使用url.openConnection代码,这正是您解释的原因(但在此之前,我在尝试创建url时没有出现异常,因此我现在遇到了问题)。我有以下代码:

NestableURLConnection conn = new NestableURLConnection(url); 

NestableURLConnection是我创建的自定义URLConnection。我将尝试您的解决方案,这似乎非常合适!

我使用的自定义URLConnection与协议处理程序完美配合:

public class NestableURLConnection extends URLConnection {
  protected String urlPath;
  protected boolean firstEntry = false;
  public NestableURLConnection(URL url) {
     super(url);
     urlPath = url.toString();
  }

  public NestableURLConnection() {
     super(null);
  }

  public void setURL(URL url) {
     this.url = url;
     urlPath = url.toString();
  }

  public NestableURLConnection(URL url, boolean firstEntry) {
     this(url);
     this.firstEntry = firstEntry;
  }

  @Override
  public void connect() throws IOException {
     connected = true;
  }

  private String getNestedURL() throws IOException {
     int sep = urlPath.indexOf("!/");
     int start = urlPath.indexOf(':') + 1;

     for (int i = start, end = urlPath.indexOf("/") - 1; (i = urlPath.indexOf(":", i)) < end;) {
        int cursep = urlPath.indexOf("!/", sep + 2);
        if (cursep < 0) {
           break;
        }
        sep = cursep;
        ++i;
     }

     return urlPath.substring(start, sep);
  }

  @Override
  public InputStream getInputStream() throws IOException {
     int start = urlPath.indexOf(':') + 1;
     if (start > urlPath.length() || urlPath.charAt(start) == '/') {
        return url.openStream();
     }

     if (FileUtilities.useFileOrHTTPProtocol(urlPath)) {
        return url.openStream();
     }

     int sep = urlPath.indexOf("!/");
     if (sep < 0) {
        throw new MalformedURLException("Missing separator " + urlPath);
     }

     String nestedURL = getNestedURL();

     sep = urlPath.indexOf(nestedURL) + nestedURL.length();
     int nextSep = urlPath.indexOf("!/", sep + 2);

     // Use the default Java openStream() for a file scheme.
     InputStream inputStream;
     ZipEntry inputZipEntry;
     boolean isKnownProtocol = FileUtilities.useFileOrHTTPProtocol(nestedURL);
     if (!isKnownProtocol || (firstEntry)) {
        if (firstEntry) {
           nestedURL = urlPath;
        } else {
           if (!nestedURL.contains("!/")) {
              nestedURL = "file:" + nestedURL.substring(4);
           }
        }
        inputStream = createInputStream(nestedURL);
     } else {
        String entry = nextSep < 0 ? urlPath.substring(sep + 2) : urlPath.substring(sep + 2, nextSep);

        sep = nextSep;
        nextSep = urlPath.indexOf("!/", sep + 2);

        // Go directly to the right entry in the zip file
        final ZipFile zipFile = new  ZipFile(FileUtilities.replaceEscapedSequences(nestedURL.substring(5)));
        inputZipEntry = zipFile.getEntry(entry);
        InputStream zipEntryInputStream = inputZipEntry == null ? null :   zipFile.getInputStream(inputZipEntry);
        if (zipEntryInputStream == null) {
           zipFile.close();
           // return null instead of throwing an Exception if the URL does not exist
           return null;
        }
        inputStream = new FilterInputStream(zipEntryInputStream) {
           @Override
           public void close() throws IOException {
              super.close();
             zipFile.close();
           }
        };
     }

     // Loop over the archive paths.
     LOOP:
     while (sep > 0) {
        // The entry name to be matched.
        String entry = nextSep < 0 ? urlPath.substring(sep + 2) : urlPath.substring(sep + 2, nextSep);

        // Wrap the input stream as a zip stream to scan it's contents for a match.
        // Don't use try-with-resources here because we only want to close it if there is an internal IOException
        ZipInputStream zipInputStream = new ZipInputStream(inputStream);
        while (zipInputStream.available() >= 0) {
           ZipEntry zipEntry = zipInputStream.getNextEntry();
           if (zipEntry == null) {
              break;
           } else if (firstEntry) {
              inputZipEntry = zipEntry;
              inputStream = zipInputStream;
              sep = -1;
              continue LOOP;
           } else if (entry.equals(zipEntry.getName())) {
              inputZipEntry = zipEntry;
              inputStream = zipInputStream;

              // Skip to the next archive path and continue the loop.
              sep = nextSep;
              nextSep = urlPath.indexOf("!/", sep + 2);
              continue LOOP;
           }
        }
        throw new IOException("Archive entry not found " + urlPath);
     }

     return inputStream;
  }

  private InputStream createInputStream(String nestedURL) throws IOException {
     return new URL(nestedURL).openStream();
  }

  @Override
  public OutputStream getOutputStream() throws IOException {
     return null;
  }
公共类NestableURLConnection扩展了URLConnection{
受保护的字符串路径;
受保护的布尔值firstEntry=false;
公共嵌套URL连接(URL){
超级链接(url);
urlPath=url.toString();
}
公共NestableURLConnection(){
超级(空);
}
公共无效设置URL(URL){
this.url=url;
urlPath=url.toString();
}
公共NestableURLConnection(URL,布尔值firstEntry){
此(url);
this.firstEntry=firstEntry;
}
@凌驾
public void connect()引发IOException{
连接=真;
}
私有字符串getNestedURL()引发IOException{
int sep=urlPath.indexOf(!/”;
int start=urlPath.indexOf(“:”)+1;
对于(int i=start,end=urlPath.indexOf(“/”)-1;(i=urlPath.indexOf(“:”,i))urlPath.length()| | urlPath.charAt(开始)=='/')){
返回url.openStream();
}
if(FileUtilities.useFileOrHTTPProtocol(urlPath)){
返回url.openStream();
}
int sep=urlPath.indexOf(!/”;
如果(sep<0){
抛出新的MalformedURLException(“缺少分隔符”+urlPath);
}
字符串nestedURL=getNestedURL();
sep=urlPath.indexOf(nestedURL)+nestedURL.length();
int-nextSep=urlPath.indexOf(“!/”,sep+2);
//对文件方案使用默认的Java openStream()。
输入流输入流;
Zippentry输入Zippentry;
布尔值isKnownProtocol=FileUtilities.useFileOrHTTPProtocol(nestedURL);
如果(!isKnownProtocol | | |(第一项)){
如果(首次输入){
nestedURL=urlPath;
}否则{
如果(!nestedURL.contains(!/”){
nestedURL=“文件:”+nestedURL.substring(4);
}
}
inputStream=createInputStream(nestedURL);
}否则{
String entry=nextSep<0?urlPath.substring(sep+2):urlPath.substring(sep+2,nextSep);
sep=nextSep;
nextSep=urlPath.indexOf(“!/”,sep+2);
//直接转到zip文件中的正确条目
final ZipFile ZipFile=新的ZipFile(FileUtilities.replaceScapedSequences(nestedURL.substring(5));
inputZipEntry=zipFile.getEntry(条目);
InputStream ZipPentryInputStream=InputZipPentry==null?null:zipFile.getInputStream(InputZipPentry);
if(zipEntryInputStream==null){
zipFile.close();
//如果URL不存在,则返回null而不是引发异常
返回null;
}
inputStream=新过滤器inputStream(zipEntryInputStream){
@凌驾
public void close()引发IOException{
super.close();
zipFile.close();
}
};
}
//在归档路径上循环。
循环:
而(9月>0日){
//要匹配的条目名称。
String entry=nextSep<0?urlPath.substring(sep+2):urlPath.substring(sep+2,nextSep);
//将输入流包装为zip流,以扫描其内容以查找匹配项。
//这里不要使用try with resources,因为我们只想在出现内部IOException时关闭它
ZipInputStream ZipInputStream=新的ZipInputStream(inputStream);
而(zipInputStream.available()>=0){
ZipEntry-ZipEntry=zipInputStream.getNextEntry();
if(zipEntry==null){
public class NestableURLConnection extends URLConnection {
  protected String urlPath;
  protected boolean firstEntry = false;
  public NestableURLConnection(URL url) {
     super(url);
     urlPath = url.toString();
  }

  public NestableURLConnection() {
     super(null);
  }

  public void setURL(URL url) {
     this.url = url;
     urlPath = url.toString();
  }

  public NestableURLConnection(URL url, boolean firstEntry) {
     this(url);
     this.firstEntry = firstEntry;
  }

  @Override
  public void connect() throws IOException {
     connected = true;
  }

  private String getNestedURL() throws IOException {
     int sep = urlPath.indexOf("!/");
     int start = urlPath.indexOf(':') + 1;

     for (int i = start, end = urlPath.indexOf("/") - 1; (i = urlPath.indexOf(":", i)) < end;) {
        int cursep = urlPath.indexOf("!/", sep + 2);
        if (cursep < 0) {
           break;
        }
        sep = cursep;
        ++i;
     }

     return urlPath.substring(start, sep);
  }

  @Override
  public InputStream getInputStream() throws IOException {
     int start = urlPath.indexOf(':') + 1;
     if (start > urlPath.length() || urlPath.charAt(start) == '/') {
        return url.openStream();
     }

     if (FileUtilities.useFileOrHTTPProtocol(urlPath)) {
        return url.openStream();
     }

     int sep = urlPath.indexOf("!/");
     if (sep < 0) {
        throw new MalformedURLException("Missing separator " + urlPath);
     }

     String nestedURL = getNestedURL();

     sep = urlPath.indexOf(nestedURL) + nestedURL.length();
     int nextSep = urlPath.indexOf("!/", sep + 2);

     // Use the default Java openStream() for a file scheme.
     InputStream inputStream;
     ZipEntry inputZipEntry;
     boolean isKnownProtocol = FileUtilities.useFileOrHTTPProtocol(nestedURL);
     if (!isKnownProtocol || (firstEntry)) {
        if (firstEntry) {
           nestedURL = urlPath;
        } else {
           if (!nestedURL.contains("!/")) {
              nestedURL = "file:" + nestedURL.substring(4);
           }
        }
        inputStream = createInputStream(nestedURL);
     } else {
        String entry = nextSep < 0 ? urlPath.substring(sep + 2) : urlPath.substring(sep + 2, nextSep);

        sep = nextSep;
        nextSep = urlPath.indexOf("!/", sep + 2);

        // Go directly to the right entry in the zip file
        final ZipFile zipFile = new  ZipFile(FileUtilities.replaceEscapedSequences(nestedURL.substring(5)));
        inputZipEntry = zipFile.getEntry(entry);
        InputStream zipEntryInputStream = inputZipEntry == null ? null :   zipFile.getInputStream(inputZipEntry);
        if (zipEntryInputStream == null) {
           zipFile.close();
           // return null instead of throwing an Exception if the URL does not exist
           return null;
        }
        inputStream = new FilterInputStream(zipEntryInputStream) {
           @Override
           public void close() throws IOException {
              super.close();
             zipFile.close();
           }
        };
     }

     // Loop over the archive paths.
     LOOP:
     while (sep > 0) {
        // The entry name to be matched.
        String entry = nextSep < 0 ? urlPath.substring(sep + 2) : urlPath.substring(sep + 2, nextSep);

        // Wrap the input stream as a zip stream to scan it's contents for a match.
        // Don't use try-with-resources here because we only want to close it if there is an internal IOException
        ZipInputStream zipInputStream = new ZipInputStream(inputStream);
        while (zipInputStream.available() >= 0) {
           ZipEntry zipEntry = zipInputStream.getNextEntry();
           if (zipEntry == null) {
              break;
           } else if (firstEntry) {
              inputZipEntry = zipEntry;
              inputStream = zipInputStream;
              sep = -1;
              continue LOOP;
           } else if (entry.equals(zipEntry.getName())) {
              inputZipEntry = zipEntry;
              inputStream = zipInputStream;

              // Skip to the next archive path and continue the loop.
              sep = nextSep;
              nextSep = urlPath.indexOf("!/", sep + 2);
              continue LOOP;
           }
        }
        throw new IOException("Archive entry not found " + urlPath);
     }

     return inputStream;
  }

  private InputStream createInputStream(String nestedURL) throws IOException {
     return new URL(nestedURL).openStream();
  }

  @Override
  public OutputStream getOutputStream() throws IOException {
     return null;
  }