Использование аннотации java для анализа строки на основе индексов

Я пытаюсь разобрать строку на основе расположения символов в свойствах, что-то вроде того, что делает внешняя библиотека, такая как beanIo, но без реального использования beanIo(http://beanio.org/2.1/docs/reference/index.html#BuilderApiAndAnnotations)

Я хотел бы использовать аннотации, и именно здесь я борюсь, я не думаю, что понимаю их достаточно. Мой вариант использования:

String stringToParse = "0
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}
>
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

На самом деле не очень понимаю использование пользовательских аннотаций, поэтому даже не уверен, что вышеизложенное - это то, как я должен это делать.


person Snedden27    schedule 10.03.2020    source источник
comment
На самом деле вы ищете учебник по процессору аннотаций Java, также известный как APT, процессор, который вам нужно построить, не сложный, поэтому сначала вручную напишите код, который вы ожидаете сгенерировать, а затем, следуя любому учебнику по APT, напишите процессор для генерации кода вместо этого.   -  person Ahmad Bawaneh    schedule 11.03.2020
comment
спасибо, присмотрюсь   -  person Snedden27    schedule 11.03.2020


Ответы (2)


Это плохой дизайн для того, что вы пытаетесь сделать. Если вы собираетесь компилировать такие вещи в код, вам лучше создать утилиту для прямого анализа этих значений. Вы ничего не можете сделать, используя аннотации в этом контексте. Что-то вроде этого намного проще читать, понимать и поддерживать:

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;
}
person Ryan    schedule 10.03.2020
comment
спасибо за ваш ответ, я хочу пойти с аннотацией, так как я думаю, что проще сохранить конфигурацию в самой аннотации, что касается моих реальных сценариев, у меня есть куча файлов с разными типами строк, которые я должен анализировать, это было бы мне проще сохранить конфигурацию в аннотациях, а не в отдельном файле конфигурации. Также я бы предпочел @Field (at = 2, length = 6), а не вызов конструктора или функции. - person Snedden27; 10.03.2020

Вот что я в итоге сделал, пожалуйста, не стесняйтесь комментировать возможные улучшения:

Я отказался от класса записи и получил только аннотацию «Поле», я переименовал его в «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;
    }
}
person Snedden27    schedule 11.03.2020
comment
Вы закончили тем, что сделали это в размышлении. - person Ahmad Bawaneh; 12.03.2020