2011-12-23 10 views
6

私はアプリケーション(特にBukkit Minecraftサーバー用のプラグイン)を作成しています。これを行うには、アプリケーションのJARから.propertiesファイルにアクセスする必要があります。これは私が奇妙な問題に直面するところです。開発用PCでプログラムをテストすると、うまく動作します。 .propertiesファイルがロードされ、すべて正常です。しかし、私がテストしている他のコンピュータでは、アプリケーションを起動しようとしましたが、プロパティをロードできず、InputStreamnullです。ファイルをロードする方法は次のとおりです。すべてのコンピュータ上のJAR内のリソースにアクセスできない

public class Points { 
    private HashMap<String, MessageFormat> messages; 

    public Points() { 
     buildMessages(); 
    } 

public static void buildMessages() { 
     Properties messageProps = new Properties(); 
     InputStream in = Points.class.getResourceAsStream("resources/messages.properties"); 
     messages = new HashMap<String, MessageFormat>(); 
     Enumeration en; 
     try { 
      messageProps.load(in); 
     } catch(IOException ex) { 
      System.err.println("Couldn't read message properties file!"); 
      return; 
     } catch(NullPointerException ex) { 
      System.err.println("Couldn't read message properties file!"); 
      if(in == null) 
       System.out.println("IOStream null"); 
      return; 
     } 
     en = messageProps.propertyNames(); 
     while(en.hasMoreElements()) { 
      String key = (String)en.nextElement(); 
      String prop = messageProps.getProperty(key); 
      MessageFormat form = new MessageFormat(prop.replaceAll("&", 
       "\u00a7").replaceAll("`", "")); 
      messages.put(key, form); 
     } 
    } 
} 

私はいくつかの無関係のコードを省略しましたが、それはその要点です。次のようにJARの構造は次のとおりです。私のPC上で

com/ 
     pvminecraft/ 
      points/ 
       Points.java <-- The class where the file is loaded 
       resources/ 
        messages.properties <-- The file being loaded 

ファイルがresources/messages.propertiesからロードされたが、他のファイルに、InputStreamはnullで、かつNullPointerExceptionのための私のcatchブロックが実行されています。何が問題を引き起こしているのでしょうか、どのように修正できますか?ありがとう。

更新:フルパス(/com/pvminecraft/points/resources/messages.properties)を使用しても、同じ問題は引き続き発生します。

アップデート2:ここではフルスタックトレースです:

java.lang.NullPointerException 
    at java.util.Properties$LineReader.readLine(Properties.java:435) 
    at java.util.Properties.load0(Properties.java:354) 
    at java.util.Properties.load(Properties.java:342) 
    at com.pvminecraft.points.Points.buildMessages(Unknown Source) 
    at com.pvminecraft.points.Points.onEnable(Unknown Source) 
    at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:188) 
    at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:968) 
    at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:280) 
    at org.bukkit.craftbukkit.CraftServer.loadPlugin(CraftServer.java:186) 
    at org.bukkit.craftbukkit.CraftServer.enablePlugins(CraftServer.java:169) 
    at org.bukkit.craftbukkit.CraftServer.reload(CraftServer.java:436) 
    at org.bukkit.Bukkit.reload(Bukkit.java:187) 
    at org.bukkit.command.defaults.ReloadCommand.execute(ReloadCommand.java:22) 
    at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:165) 
    at org.bukkit.craftbukkit.CraftServer.dispatchCommand(CraftServer.java:378) 
    at org.bukkit.craftbukkit.CraftServer.dispatchCommand(CraftServer.java:374) 
    at net.minecraft.server.MinecraftServer.b(MinecraftServer.java:564) 
    at net.minecraft.server.MinecraftServer.w(MinecraftServer.java:541) 
    at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:425) 
    at net.minecraft.server.ThreadServerApplication.run(SourceFile:457) 

org.bukkitorg.craftbukkitもののすべてがサーバです。 .propertiesファイルはonEnableメソッドで呼び出されたbuildMessagesメソッドにロードされ、Pointsです。

更新3:アーチLinuxの新規インストール時に、メッセージプロパティファイルが正しくロードされ、すべて正常です。リモートサーバーはUbuntu Linuxで、私の開発PCはArchです。

更新4:申し訳ありませんが、これは解決の一種です。それはローカライズされた問題のようです。私はそれが2台のコンピュータにアクセスすることができたので、そのプログラムは両方で正しく動作するからです。それは迷惑なことですが、これは私のコードやビルドスクリプトに間違っているようには見えません。私はまだ何が間違っているかを知りたがっていますが、これ以上のことはありません。私はこれを調べ続けます。みんな、ありがとう。

+0

ディレクトリ "resources"はクラスパス上にありません - Tomの答えを参照してください。しかし、 "com/pvminecraft/points/resources"というディレクトリがあります。あなたの開発環境をチェックしてください - クラスパスが面白く設定されているか、クラスパス上にあるプロパティファイルのコピーがあると思います。 – Paul

+0

スタックトレース全体を送信してください。 – Paul

+0

行番号はここにあります: 'at com.pvminecraft.points.Points.buildMessages(Unknown Source)'。あなたのJDKのバージョンは何ですか? – Kowser

答えて

2

さまざまなJavaクラスローダーとその検索パスの間の小さな微妙な感じです。 これらの詳細に進む前に、なぜこのjarファイル内で完全なパスを試してみませんか? (このようなつまり、何か:

Points.class.getResourceAsStream("com/pvminecraft/points/resources/messages.properties"); 

+3

完全パスは "/"で始まります –

+0

これは同じ変更です。私のPC上では動作しますが、他のPCでは動作しません。 –

+0

@MichaelSmith - どのようにあなたのコンピュータでそれを実行していますか? – Paul

2

Point.class.getClassLoader().getResourceAsStream("com/pvminecraft/points/resources/messages.properties");

は、最初に '/' なしでそれを試してみて、それがどこでもJVMを実行している動作するはずです。

これでうまくいかなかった場合は、ファイルをJARファイルのROOTに入れてもう一度試してみてください。

それでも動作しない場合は、このメソッドを使用してみてくださいは:

public static byte[] getFile(File zip, String fileName) throws FileNotFoundException, ZipException, IOException { 
     String filename = fileName; 

     if (!zip.exists()) { 
      throw new FileNotFoundException(zip.getName()); 
     } 
     while (filename.charAt(0) == '/' || filename.charAt(0) == '\\') { 
      filename = filename.substring(1); 
     } 

     if (filename.contains("\\")) { 
      filename = filename.replace("\\", "/"); 
     } 

     ZipFile zipFile = new ZipFile(zip); 
     Enumeration entries = zipFile.entries(); 

     ByteArrayOutputStream output; 
     byte[] result = null; 

     while (entries.hasMoreElements()) { 
      ZipEntry entry = (ZipEntry) entries.nextElement(); 

      if (entry.getName().equalsIgnoreCase(filename)) { 
       FileUtils.copyInputStream(zipFile.getInputStream(entry), output = new ByteArrayOutputStream()); 
       result = output.toByteArray(); 
       zipFile.close(); 
       output.close(); 
       return result; 
      } 
     } 

     zipFile.close(); 
     throw new FileNotFoundException(filename); 
    } 

あなたはこの

public static void copyInputStream(InputStream in, OutputStream out) throws IOException { 
    byte[] buffer = new byte[1024]; 
    int len; 
    while (((len = in.read(buffer)) >= 0)) { 
     out.write(buffer, 0, len); 
    } 
    out.flush(); 
} 

は最初の実行中瓶

String currentJar = ""; 
             // Get current jar path. Since user may rename this file, we need to do this way 
       try { 
        currentJar = (Points.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()); 
        if (currentJar.startsWith("/")) currentJar = currentJar.substring(1); 
        } catch (URISyntaxException ex) { 
        } 

のパスを取得する必要があります。 '/'なぜそれが表示されるのかは覚えていませんが、表示されますので、削除する必要があります:

最後にメソッドを呼び出します。getFile(currentJar, "PATH_TO_PROPERTIES_FILE");

使用するバイト配列があります。 ByteArrayInputStreamとして配置すれば、問題は解決されるはずです。コードは、私が作成したutilのクラスの一部であり、それはバイト配列に、なぜに、不要な読み取りですが、OFC、あなたが直接それのInputStreamは、Properties.loadに()メソッドを使用するように変更できること


。クラスのutilのfileutilsのためのZIP utilのクラスの

リンク

http://all-inhonmodman.svn.sourceforge.net/viewvc/all-inhonmodman/ModManager/src/modmanager/utility/ZIP.java?revision=292&content-type=text%2Fplain

リンク

http://all-inhonmodman.svn.sourceforge.net/viewvc/all-inhonmodman/ModManager/src/modmanager/utility/FileUtils.java?revision=294&content-type=text%2Fplain

0

あなたはまた、あなたのビルドスクリプト(Antの、Mavenの)場合を確認することIDEが結果のJARファイルからそのmessages.propertiesを削除/再配置しなかった(.classではありません)。あなたは、7zipやWinZipのようなツールを使ってJARの内容を確認することができます。

0

クラスの同じパッケージ(Point)にあるリソースを読み込んでいるため、ロードするために絶対パスを使用する必要はありません。

サーバーはプラグインのロードにあらゆる種類のキャッシュを使用していますか?これは、プラグインjarの古いバージョンがクラスパスに存在するために発生する可能性があります。サーバーが本当に正しいバージョンのjarファイルをロードしていることを確認するには、何かをコンソールに記録し、何かが起きたかどうかを確認するプラグインのバージョンを配備してみてください。

また、クラスローダー階層がサーバー内でどのように構成されているのかわかりませんが、現在のスレッドクラスローダー(通常はルート親クラスローダー)からリソースを読み込めます。他のすべての子クラスローダ)。それには絶対パスを使用する必要があります。

ClassLoader rootCL = Thread.currentThread().getContextClassLoader(); 
InputStream resource = rootCL.getResourceAsStream(
     "/com/pvminecraft/points/resources/messages.properties"); 

異なるクラスローダーの詳細については、questionを参照してください。

関連する問題