6

是否有一种完善的方法来记录 Java“属性”文件内容,包括:

  • 指定给定键的预期数据类型/内容
  • 指定应用程序是否需要密钥才能运行
  • 提供密钥含义的描述

目前,我(手动)维护一个默认的 .properties 文件,并且我在之前的评论中写了数据类型的散文描述和每个键的描述。这不会导致以编程方式访问的属性文件。

我想我正在寻找的是属性文件的“getopt”等价物......

[编辑:相关]

4

4 回答 4

3

您可以使用Apache Commons 配置包中的一些功能。它至少提供对您的属性的类型访问。

传统的 java 属性文件中只有约定。我见过的一些包括提供,就像你说的,一个示例属性文件。另一种是提供所有属性的默认配置,但被注释掉了。

如果你真的需要一些东西,也许你不是在寻找属性文件。您可以使用 XML 配置文件并指定具有数据类型和要求的模式。您可以使用 jaxb 将架构编译成 java 并以这种方式读取它。通过验证,您可以确保所需的属性在那里。

您可能希望的最好结果是当您执行应用程序时,它会读取、解析和验证文件中的属性。如果您绝对必须保持基于属性并且不想使用 xml,但需要此解析。您可以有一个辅助属性文件,其中列出了可以包含的每个属性、其类型以及是否需要。然后,您必须编写一个属性文件验证器,该验证器将接收要验证的文件以及类似于验证模式的属性文件。就像是

#list of required properties
required=prop1,prop2,prop3

#all properties and their types
prop1.type=Integer
prop2.type=String

我没有浏览过所有的 Apache 配置包,但它们通常有像这样有用的实用程序。如果您可以在其中找到可以简化此操作的内容,我不会感到惊讶。

于 2009-04-08T19:29:03.470 回答
2

签出的另一个选项是名为OWNER的项目。在那里,您可以使用类型和注释定义用作应用程序中配置对象的接口。然后,OWNER 查找和解析正确的Properties文件。因此,您可以为您的界面编写一个javadoc并将其用作文档。

于 2014-02-12T17:03:53.043 回答
1

一种简单的方法是使用示例属性文件分发您的项目,例如我的项目在 svn 中有一个“build.properties.example”,并根据需要对属性进行注释。本地正确的属性不会进入 svn。

不过,既然您提到了“getopt”,我想知道您是否真的在考虑命令行参数?如果有一个需要特定属性的“main”,我通常会将相关说明放在“useage”消息中,如果参数不正确或“-h”会打印出来。

于 2009-04-08T18:35:15.487 回答
1

我从未见过这样做的标准方法。我可能会做的是:

  • 包装或扩展java.util.Properties
  • 覆盖(扩展)或提供方法(如果包装)为每一行写出注释的存储方法(或 storeToXML 等)。
  • 具有存储属性的方法具有某种输入文件,您可以在其中描述每个属性的属性。

它不会让你对你正在做的事情有任何帮助,除了你可以用一种不同的方式来管理信息,这可能更容易处理——例如,你可以有一个程序来吐出要读入的评论。它可能会为您提供所需的编程访问,但它是一种您自己的东西。

或者它可能只是工作太多而收获太少(这就是为什么那里没有明显的东西)。

如果你可以指定你想看到的评论类型,如果我感到无聊,我可以尝试写一些东西:-)(这是我喜欢做的有趣的事情,我知道恶心:-)。

好的...我很无聊...这至少是一个开始:-)

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;


public class PropertiesVerifier
{
    private final Map<String, PropertyInfo> optionalInfo;
    private final Map<String, PropertyInfo> requiredInfo;

    {
        optionalInfo = new HashMap<String, PropertyInfo>();
        requiredInfo = new HashMap<String, PropertyInfo>();
    }

    public PropertiesVerifier(final PropertyInfo[] infos)
    {
        for(final PropertyInfo info : infos)
        {
            final Map<String, PropertyInfo> infoMap;

            if(info.isRequired())
            {
                infoMap = requiredInfo;
            }
            else
            {
                infoMap = optionalInfo;
            }

            infoMap.put(info.getName(), info);
        }
    }

    public void verifyProperties(final Properties properties)
    {
        for(final Entry<Object, Object> property : properties.entrySet())      
        {
            final String key;
            final String value;

            key   = (String)property.getKey();
            value = (String)property.getValue();

            if(!(isValid(key, value)))
            {
                throw new IllegalArgumentException(value + " is not valid for: " + key);
            }
        }
    }

    public boolean isRequired(final String key)
    {
        return (requiredInfo.get(key) != null);
    }

    public boolean isOptional(final String key)
    {
        return (optionalInfo.get(key) != null);
    }

    public boolean isKnown(final String key)
    {
        return (isRequired(key) || isOptional(key));
    }

    public Class getType(final String key)
    {
        final PropertyInfo info;

        info = getPropertyInfoFor(key);

        return (info.getType());
    }

    public boolean isValid(final String key,
                           final String value)
    {
        final PropertyInfo info;

        info = getPropertyInfoFor(key);

        return (info.verify(value));
    }

    private PropertyInfo getPropertyInfoFor(final String key)
    {
        PropertyInfo info;

        info = requiredInfo.get(key);

        if(info == null)
        {
            info = optionalInfo.get(key);

            if(info == null)
            {
                // should be a better exception maybe... depends on how you 
                // want to deal with it
                throw new IllegalArgumentException(key + " 
                                                   is not a valid property name");
            }
        }

        return (info);
    }

    protected final static class PropertyInfo
    {
        private final String name;
        private final boolean required;
        private final Class clazz;
        private final Verifier verifier;

        protected PropertyInfo(final String   nm,
                               final boolean  mandatory,
                               final Class    c)
        {
            this(nm, mandatory, c, getDefaultVerifier(c));
        }

        protected PropertyInfo(final String   nm,
                               final boolean  mandatory,
                               final Class    c,
                               final Verifier v)
        {
            // check for null
            name     = nm;
            required = mandatory;
            clazz    = c;
            verifier = v;
        }

        @Override
        public int hashCode()
        {
            return (getName().hashCode());
        }

        @Override
        public boolean equals(final Object o)
        {
            final boolean retVal;

            if(o instanceof PropertyInfo)
            {
                final PropertyInfo other;

                other  = (PropertyInfo)o;
                retVal = getName().equals(other.getName());
            }
            else
            {
                retVal = false;
            }

            return (retVal);
        }

        public boolean verify(final String value)
        {
            return (verifier.verify(value));
        }

        public String getName()
        {
            return (name);
        }

        public boolean isRequired()
        {
            return (required);
        }

        public Class getType()
        {
            return (clazz);
        }
    }

    private static Verifier getDefaultVerifier(final Class clazz)
    {
        final Verifier verifier;

        if(clazz.equals(Boolean.class))
        {
            // shoudl use a singleton to save space...
            verifier = new BooleanVerifier();
        }
        else
        {
            throw new IllegalArgumentException("Unknown property type: " + 
                                               clazz.getCanonicalName());
        }

        return (verifier);
    }

    public static interface Verifier
    {
        boolean verify(final String value);
    }

    public static class BooleanVerifier
        implements Verifier
    {
        public boolean verify(final String value)
        {
            final boolean retVal;

            if(value.equalsIgnoreCase("true") ||
               value.equalsIgnoreCase("false"))
            {
                retVal = true;
            }
            else
            {
                retVal = false;
            }

            return (retVal);
        }
    }
}

并对其进行简单的测试:

import java.util.Properties;


public class Main
{
    public static void main(String[] args)
    {
        final Properties         properties;
        final PropertiesVerifier verifier;

        properties = new Properties();
        properties.put("property.one",   "true");
        properties.put("property.two",   "false");
//        properties.put("property.three", "5");
        verifier = new PropertiesVerifier(
            new PropertiesVerifier.PropertyInfo[]
            {
                new PropertiesVerifier.PropertyInfo("property.one",   
                                                    true, 
                                                    Boolean.class),
                new PropertiesVerifier.PropertyInfo("property.two",   
                                                    false, 
                                                    Boolean.class),
//                new PropertiesVerifier.PropertyInfo("property.three", 
//                                                    true, 
//                                                    Boolean.class),
            });

        System.out.println(verifier.isKnown("property.one"));
        System.out.println(verifier.isKnown("property.two"));
        System.out.println(verifier.isKnown("property.three"));

        System.out.println(verifier.isRequired("property.one"));
        System.out.println(verifier.isRequired("property.two"));
        System.out.println(verifier.isRequired("property.three"));

        System.out.println(verifier.isOptional("property.one"));
        System.out.println(verifier.isOptional("property.two"));
        System.out.println(verifier.isOptional("property.three"));

        System.out.println(verifier.getType("property.one"));
        System.out.println(verifier.getType("property.two"));

        // System.out.println(verifier.getType("property.tthree"));
        System.out.println(verifier.isValid("property.one", "true"));
        System.out.println(verifier.isValid("property.two", "false"));
        // System.out.println(verifier.isValid("property.tthree", "5"));


        verifier.verifyProperties(properties);
    }
}
于 2009-04-08T19:22:50.503 回答