记录可用/所需 Java 属性文件内容的最佳实践

发布于 2024-07-16 04:23:23 字数 350 浏览 5 评论 0原文

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

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

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

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

[编辑:相关]

Is there a well-established approach for documenting Java "properties" file contents, including:

  • specifying the data type/contents expected for a given key
  • specifying whether a key is required for the application to function
  • providing a description of the key's meaning

Currently, I maintain (by hand) a .properties file that is the default, and I write a prose description of the data type and description of each key in a comment before. This does not lead to a programmatically accessible properties file.

I guess what I'm looking for is a "getopt" equivalent for properties files...

[EDIT: Related]

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

傲性难收 2024-07-23 04:23:23

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

传统的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 配置包,但它们通常有这样有用的实用程序。 如果您能在那里找到可以简化此操作的东西,我不会感到惊讶。

You could use some of the features in the Apache Commons Configuration package. It at least provides type access to your properties.

There are only conventions in the traditional java properties file. Some I've seen include providing, like you said, an example properties file. Another is to provide the default configuration with all the properties, but commented out.

If you really want to require something, maybe you're not looking for a properties file. You could use an XML configuration file and specify a schema with datatypes and requirements. You can use jaxb to compile the schema into java and read it i that way. With validation you can make sure the required properties are there.

The best you could hope for is when you execute your application, it reads, parses, and validates the properties in the file. If you absolutely had to stay properties based and didn't want to go xml, but needed this parsing. You could have a secondary properties file that listed each property that could be included, its type, and whether it was required. You'd then have to write a properties file validator that would take in a file to validate as well as a validation schema-like properties file. Something like

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

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

I haven't looked through all of the Apache Configuration package, but they often have useful utilities like this. I wouldn't be surprised if you could find something in there that would simplify this.

梦里兽 2024-07-23 04:23:23

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

Another option to check out is the project called OWNER. There, you define the interface that serves as the configuration object in your application, using types and annotations. Then, OWNER does the finding and parsing of the correct Properties file. Thus, you could write a javadoc for your interface and use that as the documentation.

破晓 2024-07-23 04:23:23

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

  • 包装或扩展 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);
    }
}

I have never seen a standard way of doing it. What I would probably do is:

  • wrap or extend the java.util.Properties class
  • override (of extending) or provide a method (if wrapping) the store method (or storeToXML, etc) that writes out a comment for each line.
  • have the method that stores the properties have some sort of input file where you describe the properties of each one.

It doesn't get you anything over what you are doing by hand, except that you can manage the information in a different way that might be easier to deal with - for example you could have a program that spit out the comments to read in. It would potentially give you the programmatic access that you need, but it is a roll-your-own sort of thing.

Or it might just be too much work for too little to gain (which is why there isn't something obvious out there).

If you can specify the sort of comments you want to see I could take a stab at writing something if I get bored :-) (it is the sort of thing I like to do for fun, sick I know :-).

Ok... I got bored... here is something that is at least a start :-)

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);
        }
    }
}

And a simple test for it:

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);
    }
}
萝莉病 2024-07-23 04:23:23

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

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

One easy way is to distribute your project with a sample properties file, e.g. my project has in svn a "build.properties.example",with properties commented as necessary. The locally correct properties don't go into svn.

Since you mention "getopt", though, I'm wondering if you're really thinking of cmd line arguments? If there's a "main" that needs specific properties, I usually put it the relevant instructions in a "useage" message that prints out if the arguments are incorrect or "-h".

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文