2015-01-07 52 views
0

我有一個屬性文件,該文件是這樣的 -如何安全地讀取Java中的屬性文件?

[email protected] 
[email protected] 

# can be separated by comma 
whichServer=UserServer,GuestServer 

maxTestInSec=120 
numberOfUsers=1000 

現在我讀的Java這樣這個屬性文件,如果一切都正確設置它的工作原理 -

private static final Properties prop = new Properties(); 

private static String emailFrom; 
private static String emailTo; 
private static List<String> whichServer; 
private static String maxTestInSec; 
private static String numberOfUsers; 

public static void main(String[] args) { 
    readConfig(args); 
} 

private void readConfig(String[] args) throws FileNotFoundException, IOException { 
    if (!TestUtils.isEmpty(args) && args.length != 0) { 
     prop.load(new FileInputStream(args[0])); 
    } else { 
     prop.load(TestTask.class.getClassLoader().getResourceAsStream("config.properties")); 
    } 

    emailFrom = prop.getProperty("emailFrom").trim(); 
    emailTo = prop.getProperty("emailTo").trim(); 
    whichServer = Arrays.asList(prop.getProperty("whichServer").trim().split(",")); 
    maxTestInSec = prop.getProperty("maxTestInSec").trim(); 
    numberOfUsers = prop.getProperty("numberOfUsers").trim(); 
} 

問題陳述: -

我需要確保如果任何屬性值丟失,那麼我想使用默認值,如果有任何機會該屬性被註釋掉,那麼也我想使用默認值,但我會記錄一條警告消息,說明屬性丟失或空,所以使用默認值。我試圖覆蓋所有角落的情況下讀取文件 -

  • 現在讓我們假設,如果我不指定值來任我在上面的文件屬性,然後我想用默認值屬性我沒有提供並記錄爲警告,指出沒有爲此屬性提供值,因此使用默認值。例如:比方說,如果我沒有爲emailFrom字段中提供任何值,那麼我想用默認值[email protected]爲和他人類似的事情。所有屬性的默認值是:

[email protected]

[email protected]

whichServer = UserServer的

maxTestInSec = 30

numberOfUsers = 500

  • 此外,如果任何的屬性被註釋掉那麼上面的代碼將通過NPE異常。我如何在該場景中使用默認值?

我應該開始使用命令行解析器呢?什麼是處理這些東西最好和乾淨的方式?

我不希望有很多的if塊添加一張支票,然後設置的默認值。

回答

0

在財產的情況下已被註釋掉,回報將是空的,所以簡單地做一個空檢查。

if (prop.getProperty("name")==null) 

如果值未填滿,請檢查其是否等於修剪操作後的空白空間。

if (prop.getProperty("name").trim().equals("")) 
+0

感謝您的建議。有了這種方法,如果我的配置文件中有20個屬性,那麼這意味着我需要有40個如果塊?有沒有其他乾淨的方式來做到這一點? – john

+0

您可以使用下面的枚舉來獲取所有屬性名稱。 Enumeration en = prop.propertyNames(); (en.hasMoreElements()) { System.out.println(en.nextElement()); } 並確保您的所有屬性都存在。 – robin

0

在實際使用之前,您可以嘗試將該屬性兌換爲該地圖上的靜態地圖和進程。

private Map<String, String> rawProps = new HashMap<String, String>; 
public static Map<String, String> actualProps = new HashMap<String, String>; 

static { 
    checkMapForNullAndReport(); 
} 

private static void checkMapForNullAndReport() { 
    // Null logic and Reporting logic 
    // Empty rawProps and populate the actualProps 
} 

這樣的事情會爲你工作,我相信。

1

從Java 8開始,最簡單的事情就是使用getOrDefault(),它可以讓你指定get站點的默認值。例如:

String email = properties.getOrDefault("emailFrom", "[email protected]"); 

這乾淨簡潔,但意味着您需要在您訪問屬性的任何地方指定默認值。

如果這不會爲你工作(即你會讀取來自屬性的值對象不止一次),你可以使用內置的支持,默認值-notice,需要一個defaultProperties對象constructor。這使您可以構建包含默認值的Properties對象,然後在加載用戶的屬性文件時,如果用戶未指定值,它將回到默認值。

private static final Properties DEFAULTS = new Properties(); 
static { 
    DEFAULTS.setProperty("emailFrom", "[email protected]"); 
} 

public Properties getProperties() { 
    Properties props = new Properties(DEFAULTS); 
    props.load(...); 
    return props; 
} 

只需注意這不是等同於Map的構造是如何工作的 - 默認值留下作爲一個獨立的地圖,只有.getProperty()還查詢默認值;在Map中定義的方法,如.get()則沒有。其中的原因有很多它是Properties一個可怕的決定延長Hashtable,但是這就是生活......


這些選項工作,但他們都容易出錯,因爲一)Properties是可變的和b)只有一些公開的方法回落到default實例。我寧願不要直接暴露Properties對象,而是使用類型安全的方法創建一個包裝類,以暴露我的應用程序將關心的值。這是一個更多的輸入,但更安全的工作。這將是這個樣子:

public class ApplicationSettings { 
    private final Properties properties = new Properties(); 
    public ApplicationSettings() { 
    properties.load(...); 
    } 

    public String emailFrom() { 
    // simple methods are concise, and encode the default right inline 
    return properties.getOrDefault("emailFrom", "[email protected]"); 
    } 

    public int getMaxTestSeconds() { 
    // You can do more complex validation if you want, too 
    String value = properties.get("maxTestInSec"); 
    if (value == null) { 
     return 30; 
    } 
    int maxTestSeconds = Integer.parseInt(value); 
    if (maxTestSeconds <= 0) { 
     // could instead log a warning and return the default if you want 
     throw new IllegalStateException(
      "maxTestInSec must be positive - was " + maxTestSeconds); 
    } 
    return maxTestSeconds; 
    } 
} 

如果你需要,你也可以將它們添加到Properties對象之前暴露setter方法是類似的驗證值,雖然在默認情況下讓一切只讀通常是一個很好的做法。