2010-11-08 29 views
14

tôi sử dụng mã này trong chương trình của tôi để tải tập tin một thuộc tính:jar thực thi sẽ không tìm thấy các thuộc tính tập tin

Properties properties = new Properties(); 
URL url = new App().getClass().getResource(PROPERTIES_FILE); 
properties.load(url.openStream()); 

Mã này chạy tốt trong Eclipse. Sau đó, tôi gói chương trình vào một JAR có tên MyProgram.jar, và chạy nó, tôi nhận được một NullPointerException ở dòng thứ hai. JAR không chứa tệp thuộc tính, cả hai đều nằm trong cùng một thư mục. Tôi đang sử dụng Maven để tạo ra JAR. Làm cách nào để khắc phục sự cố này?

CẬP NHẬT: Tôi không muốn thêm tệp thuộc tính vào JAR, vì nó sẽ được tạo tại thời điểm triển khai.

+2

Lưu ý phụ: Có lý do nào bạn đang sử dụng 'getResource()' thay vì 'getResourceAsStream()', vì bạn chỉ sử dụng nó làm luồng? – Powerlord

+1

Không, tôi không có lý do cụ thể nào. –

+0

Làm thế nào để bạn chạy bình của bạn? Nếu thông qua java -jar, bạn có thể thử java -cp ./MyProgram.jar và xem nó có hoạt động không? –

Trả lời

23

BalusC là đúng, bạn cần hướng dẫn Maven tạo MANIFEST.MF với thư mục hiện tại (.) trong mục nhập Class-Path:.

Giả sử bạn vẫn đang sử dụng hội Plugin Maven và jar-with-dependencies mô tả để xây dựng JAR thực thi, bạn có thể nói với các plugin để làm như vậy bằng cách sử dụng sau đây:

<plugin> 
    <artifactId>maven-assembly-plugin</artifactId> 
    <version>2.2</version> 
    <configuration> 
     <descriptorRefs> 
     <descriptorRef>jar-with-dependencies</descriptorRef> 
     </descriptorRefs> 
     <archive> 
     <manifest> 
      <mainClass>com.stackoverflow.App</mainClass> 
     </manifest> 
     <manifestEntries> 
      <Class-Path>.</Class-Path> <!-- HERE IS THE IMPORTANT BIT --> 
     </manifestEntries> 
     </archive> 
    </configuration> 
    <executions> 
     <execution> 
     <id>make-assembly</id> <!-- this is used for inheritance merges --> 
     <phase>package</phase> <!-- append to the packaging phase. --> 
     <goals> 
      <goal>single</goal> <!-- goals == mojos --> 
     </goals> 
     </execution> 
    </executions> 
    </plugin> 
+0

Nếu bạn không sử dụng plugin lắp ráp maven, hãy cho tôi biết và tôi sẽ cập nhật câu trả lời của mình. –

+0

Với phần 'executions', tôi không phải chạy' mvn assembly: assembly' một cách riêng biệt? Nhân tiện, cảm ơn bạn đã trả lời tất cả câu hỏi của tôi về Maven. –

+1

@HaiMinhNguyen: Thực tế, 'thực thi' ở trên liên kết mục tiêu' đơn' trên pha 'gói'. Kết quả là, chạy 'mvn package' không tạo assembly. Oh, và bạn được chào đón. –

2

EDIT: đây là để đáp ứng với nhận xét của bạn:

Bạn cần phải chắc chắn rằng các tập tin nằm ngay trục đường dẫn lớp với gốc phù hợp cho gọi java mà sao lưu các tập tin jar. nếu con đường của bạn là

stuff/things.properties

và vị trí thời gian chạy là

/opt/myapp/etc/stuff/things.properties

và file jar là trong

/opt/myapp/bin/myjar

sau đó bạn cần phải khởi động như

/path/to/java -cp "/opt/myapp/etc:/opt/myapp/bin/myjar.jar" my.pkg.KavaMain

làm việc với loại cấu hình này có thể cực kỳ khó hiểu môi trường, may mắn thay, có maven exec plugin sẽ giúp bạn có được đúng loại kịch bản khởi chạy.

gốc trả lời:

Bạn muốn đọc về the maven resources plugin.

Về cơ bản bạn muốn thêm một cái gì đó như thế này:

<plugin> 
     <artifactId>maven-jar-plugin</artifactId> 
     <configuration> 
       <resources> 
         <resource> 
           <directory>src/main/java</directory> 
           <includes> 
             <include>**/*properties</include> 
           </includes> 
         </resource> 
       </resources> 
     </configuration> 
<plugin> 

để pom.xml của bạn giả định rằng bạn đang tập tin propertis là với nguồn java của bạn - thực sự nó phải ở trong src/main/nguồn lực.

+0

Cảm ơn, nhưng tôi không muốn thêm tệp thuộc tính vào JAR. Nó sẽ được thay đổi vào thời gian triển khai. –

+0

Theo chỉnh sửa của bạn: đối số '-cp' được bỏ qua ** khi sử dụng đối số' -jar'. Nó thực sự có trong tệp 'MANIFEST.MF' :) – BalusC

+0

@BalusC righto, cố định. Không thể đi vào MANIFEST.MF nếu nó có thể di chuyển trong thời gian chạy. – lscoughlin

17

Có hai cách giải quyết :

  1. Không sử dụng JAR như executabele JAR, nhưng như thư viện.

    java -cp .;filename.jar com.example.YourClassWithMain 
    
  2. Lấy vị trí gốc của tệp JAR và lấy tệp thuộc tính từ tệp đó.

    URL root = getClass().getProtectionDomain().getCodeSource().getLocation(); 
    URL propertiesFile = new URL(root, "filename.properties"); 
    Properties properties = new Properties(); 
    properties.load(propertiesFile.openStream()); 
    

Không ai trong số cả hai đều cách tiếp cận khuyến khích!Cách tiếp cận khuyên là phải có các mục sau đây trong tập tin JAR /META-INF/MANIFEST.MF:

Class-Path: . 

Sau đó, nó sẽ có sẵn như là nguồn classpath theo cách thông thường. Bạn sẽ thực sự phải hướng dẫn Maven bằng cách nào đó để tạo ra tệp MANIFEST.MF như thế.

+0

Rất tiếc, tôi đã thử tùy chọn đầu tiên trước nhưng tôi đã sử dụng. COMMA filename.jar. Có lẽ đó là lý do tại sao nó không hoạt động. Cảm ơn bạn đã giúp đỡ. –

+0

Có một lý do để tránh Classpath - cụ thể là nếu nội dung thay đổi giữa các lần đọc. Trình tải tài nguyên lưu trữ nội dung đầu tiên –

0

Tôi đã có một vấn đề tương tự, và chủ đề này là một trợ giúp lớn! FYI, tôi đã sửa đổi tệp xây dựng Ant của mình để thực hiện việc tạo bản kê, sau đó chỉ định biểu hiện đó khi JAR-ing mã phía máy chủ của tôi:

<!-- Create a custom MANIFEST.MF file, setting the classpath. --> 
<delete file="${project.base.dir}/resources/MANIFEST.MF" failonerror="false"/> 
<manifest file="${project.base.dir}/resources/MANIFEST.MF"> 
    <attribute name="Class-Path" value="." /> 
</manifest> 

<!-- JAR the server-side code, using the custom manifest from above. --> 
<jar destfile="services/${name}.aar" manifest="${project.base.dir}/resources/MANIFEST.MF"> 
[....] 
Các vấn đề liên quan