【问题标题】:Using java annotation to parse a String based on Indices使用java注解根据索引解析字符串
【发布时间】:2020-03-10 19:36:39
【问题描述】:

我正在尝试将基于字符位置的行解析为属性,就像 beanIo 这样的外部库所做的那样,但没有真正使用 beanIo(http://beanio.org/2.1/docs/reference/index.html#BuilderApiAndAnnotations)

我想使用注释,这是我苦苦挣扎的地方,我认为我对它们的理解还不够。 我的用例:

String stringToParse = "0_2_4_MYNAME_MYAGE_";

解析上述字符串后我要构建的对象应该是这样的:

Record record = new Record(stringToParse); // this should create a key value pairs
/*record = < 
     "Age":  Field{name:"Age",value:"MYAGE", at:13, length:5}
     "Name": Field{name:"Name",value:"MYNAME", at:6, length:6}
>

我想通过注释来实现这一点,尽管我不完全理解它们是如何被阅读或应该被阅读的,这就是我现在所拥有的:

我的字段注释

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface  Field {
    public String name();
    public int at();
    public int length();
    public String value() default "[unassigned]"; //  should be determined using the other values, not passed-in
}

我的记录注释:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Record {
  //Not sure what should goes here. Maybe: public HashMap<String, Field> record
}

这就是我在课堂上使用它的方式

@Record
public class PersonInfoLine {
   @Field(at = 5, length = 6)
   private String name;

   @Field(at = 13, length = 5)
   private String age;
}

再次,当我用字符串实例化 PersonInfoLine 时,我想获取“姓名”和“年龄”,类似于:

String stringToParse = "0_2_4_MYNAME_MYAGE_";

PersonInfoLine personInfoLine = new PersonInfoLine(stringToParse);
String name = personInfoLine.record.get("name").value; //MYNAME
String age = personInfoLine.record.get("age").value; //MYAGE

不太了解自定义注释的用法,所以甚至不确定上面是我应该怎么做的..

【问题讨论】:

  • 您实际上是在寻找一个 java 注释处理器教程,也就是 APT,您需要构建的处理器并不难,所以首先手动编写您希望生成的代码,然后按照任何 APT 教程编写一个处理器来生成代码。
  • 谢谢,会调查一下

标签: java spring annotations annotation-processing


【解决方案1】:

对于您正在尝试做的事情来说,这是一个糟糕的设计。如果您要将这些内容编译到代码中,最好创建一个实用程序来直接解析这些值。在这种情况下使用注释你什么也做不了。这样的东西更容易阅读、理解和维护:

public static void main(String [] args) {
    System.out.println(resolveValue("0_2_4_MYNAME_MYAGE_", 6, 6, "MUD"));
    System.out.println(resolveValue("", 6, 6, "MUD"));
    System.out.println(resolveValue("0_2_4_MYNAME_MYAGE_", 13, 5, "DIRT"));
    System.out.println(resolveValue("0_2_4_MYNAME_", 13, 5, "DIRT"));
}

private static String resolveValue(String data, int start, int length, String defaultValue) {
    try {
        return data.substring(start, start + length);
    } catch (Exception e) {

    }
    return defaultValue;
}

【讨论】:

  • 感谢您的回复,我想使用注释,因为我认为在注释本身中保存配置更容易,至于我的真实场景,我有一堆具有不同线型的文件我必须解析,我更容易将配置保存在注释中而不是单独的配置文件中,而且我更喜欢 @Field(at=2, length=6) 而不是调用构造函数或函数。
【解决方案2】:

这是我最终做的,请随时评论可能的改进:

我放弃了记录类并且只有“字段”注释,我将其重命名为“LineField”以解决与本地“字段”类的冲突

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface  LineField {
    public int at();
    public int length();
}

从我的消费者类中调用一个实用函数来制作 fieldName-fieldValue 的映射

public class Person {
    private static Field[] fields = BatchDetail2.class.getDeclaredFields();

    @LineField(at = 0, length = 8, literal = "6")
    private String name;

    @LineField(at = 12, length = 2)
    private String age;

    private  HashMap<String, String> fieldNameValueMap;


    public BatchDetail2(String personLine){ //personLine = "SAMUEL__234_31";
        fieldNameValueMap = LineProcessorUtil.getFieldValueMap(fields, personLine);
        name = fieldNameValueMap.get("recordTypeCode"); //SAMUEL__
        age = fieldNameValueMap.get("dfiAccountNumber"); //31

    }

}

我的实用类:

public class LineProcessorUtil {

    public static String getFieldValue(LineField field, String rawString){
        int startIndex = field.at();
        int endIndex = startIndex + field.length();
        StringBuilder sb = new StringBuilder(rawString);
        return sb.substring(startIndex, endIndex);
    }

    public static HashMap<String, String> getFieldValueMap(Field[] fields, String rawString){
        HashMap<String, String> map = new HashMap<>();

        for(Field field:fields){
            if(field.isAnnotationPresent(LineField.class)){
                String fieldName = field.getName();
                LineField lineField = field.getAnnotation(LineField.class);
                String fieldValue = getFieldValue(lineField, rawString);
                map.put(fieldName, fieldValue);

            }
        }

        return map;
    }
}

【讨论】:

  • 你最终是在反思中完成的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多