创建一个类名+字符串值到类型值的解析器

安东尼:

我正在尝试编写一种方法,该方法可以接受String类名和String值,并返回表示为该String的值。

输入示例:

parse("java.lang.String", "abc") -> String "ABC"
parse("java.lang.Boolean", "FALSE") -> Boolean FALSE
parse("java.lang.Integer", "123") -> Integer 123
parse("com.me.Color", "RED") -> enum Color.RED

我发现如果使用包含assignableFrom调用的if块,则可以实现此目的。但是宁愿编写更可扩展的内容,因此明天添加新的解析器并不那么困难。

这就是我现在所拥有的:

    String stringClassName = //stringified full class name
    String value = //value to parse
    Class<?> fieldType = Class.forName(stringClassName)
    if (fieldType.isAssignableFrom(String.class)) {
      return value;
    } else if (fieldType.isAssignableFrom(Boolean.class)) {
      return Util.toBoolean(value);
    } else if (fieldType.isEnum()) {
      return Util.toEnum(fieldType, value);
    } else {
      // throw exception
    }
codeflush.dev:

有多种方法可以做到这一点。例如:

您可以有一个名为 Parser

package example;

public interface Parser {

    boolean canParse(String fullQualifiedClassName);
    Object parse(String fullQualifiedClassName, String value) throws ParseException;

    class ParseException extends Exception {

        public ParseException(String msg) {
            super(msg);
        }

        public ParseException(Exception cause) {
            super(cause);
        }
    }
}

并以枚举或以其他方式静态定义的所有默认实现:

package example;

public enum DefaultParser implements Parser {

    STRING {
        @Override
        public boolean canParse(String fullQualifiedClassName) {
            return isClassAssignableFromClassName(fullQualifiedClassName, String.class);
        }

        @Override
        public Object parse(String fullQualifiedClassName, String value) throws ParseException {
            return value;
        }
    },
    ENUM {
        @Override
        public boolean canParse(String fullQualifiedClassName) {
            return isClassAssignableFromClassName(fullQualifiedClassName, Enum.class);
        }

        @Override
        public Object parse(String fullQualifiedClassName, String value) throws ParseException {
            final Class<? extends Enum> clazz;
            try {
                clazz = (Class<? extends Enum>) Class.forName(fullQualifiedClassName);
            } catch (ClassNotFoundException e) {
                throw new ParseException(e);
            }

            return Enum.valueOf(clazz, value);
        }
    },
    BOOLEAN {
        @Override
        public boolean canParse(String fullQualifiedClassName) {
            return isClassAssignableFromClassName(fullQualifiedClassName, Boolean.class);
        }

        @Override
        public Object parse(String fullQualifiedClassName, String value) throws ParseException {
            return value.toLowerCase().equals("true");
        }
    };

    private static boolean isClassAssignableFromClassName(String fullQualifiedClassName, Class<?> clazz) {
        try {
            return clazz.isAssignableFrom(Class.forName(fullQualifiedClassName));
        } catch (ClassNotFoundException e) {
            return false;
        }
    }
}

以及ParentParser将多个解析器组合为一个的实现:

package example;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class ParentParser implements Parser {

    private final List<Parser> parsers;

    public ParentParser() {
        this.parsers = new ArrayList<>();
        this.parsers.addAll(Arrays.asList(DefaultParser.values()));
    }

    public void register(Parser parser) {
        this.parsers.add(parser);
    }

    @Override
    public boolean canParse(String fullQualifiedClassName) {
        return findParser(fullQualifiedClassName).isPresent();
    }

    @Override
    public Object parse(String fullQualifiedClassName, String value) throws ParseException {
        return findParser(fullQualifiedClassName)
              .orElseThrow(() -> new ParseException("no registered parser found for class=" + fullQualifiedClassName))
              .parse(fullQualifiedClassName, value);
    }

    private Optional<Parser> findParser(String fullQualifiedClassName) {
        return this.parsers.stream().filter(parser -> parser.canParse(fullQualifiedClassName)).findAny();
    }
}

然后您可以像这样使用它:

package example;

import example.Parser.ParseException;

public class Example {

    public static void main(String[] args) throws ParseException {
        final ParentParser parser = new ParentParser();

        System.out.println(parser.parse("java.lang.String", "hello world"));
        System.out.println(parser.parse("java.lang.Boolean", "true"));
        System.out.println(parser.parse("java.time.DayOfWeek", "TUESDAY"));
    }
}

您可以添加更多解析器,例如使用Jackson(JSON)的解析器:

package example;

import com.fasterxml.jackson.databind.ObjectMapper;
import example.Parser.ParseException;

import java.io.IOException;

public class Example {

    public static void main(String[] args) throws ParseException {
        final ParentParser parser = new ParentParser();

        System.out.println(parser.parse("java.lang.String", "hello world"));
        System.out.println(parser.parse("java.lang.Boolean", "true"));
        System.out.println(parser.parse("java.time.DayOfWeek", "TUESDAY"));

        parser.register(new JacksonParser());

        System.out.println(parser.parse("java.util.Map", "{\"key\":\"value\"}"));
    }

    private static class JacksonParser implements Parser {

        private static final ObjectMapper MAPPER = new ObjectMapper();

        @Override
        public boolean canParse(String fullQualifiedClassName) {
            final Class<?> clazz;
            try {
                clazz = Class.forName(fullQualifiedClassName);
            } catch (ClassNotFoundException e) {
                return false;
            }

            return MAPPER.canDeserialize(MAPPER.constructType(clazz));
        }

        @Override
        public Object parse(String fullQualifiedClassName, String value) throws ParseException {
            try {
                return MAPPER.readValue(value, Class.forName(fullQualifiedClassName));
            } catch (ClassNotFoundException | IOException e) {
                throw new ParseException(e);
            }
        }
    }
}

请注意,这当然可以根据您的需要进行优化。如果您的Parser-Implementation只能解析静态类型列表,并且每个类只有一个Parser-Implementation,则应将更List<Parser>改为Map<Class<?>, Parser>并将register-Method更改register(Class<?> clazz, Parser parser)为例如

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

另一个解析器中的C字符串解析器

如何使用jq解析器提取json对象中的一部分字符串值

如何在文档字符串中为PyCharm解析器指定类或函数类型

使用scala packrat解析器解析一个简单的字符串

创建一个循环以扫描数组的值并将其与元素的类名匹配

无法转换“字符串”类型的值?到预期的参数类型“类?”

C#如何创建一个存储文本框中的字符串值的类

创建两个ForeignKey到一个类

Python如何创建一个包装任何值的类

创建一个允许调整基值的Attribute类?

创建一个Tkinter类并等待返回值

创建一个返回随机值的 Dice 类

创建字符串解析器以解析嵌套结构

编译器无法识别类字符串值等于另一个字符串值

如何创建一个查询来查找 MongoDB 中字符串类型的 2 个数字之间的值

从字符串[java]创建一个已创建类的ArrayList

根据另一个字符串属性的值解析一个属性的动态类型

使用数组值创建一个SimpleXML值字符串

拆分一个字符串值,然后使用 pandas 创建一个新值

如何创建一个具有将字符串输入作为文件名的函数的类,然后播放声音文件?

为什么我会得到一个字符串和一个 Kotlin 值类的类型不匹配?

与普通类型的变量数创建一个类

如何创建一个不是类型实例的类?

用可选的通用类型<T>创建一个类

C# 从类型 FullName 创建一个类的实例

将字符串数组值从Java本机接口传递到Delphi包装器类

如何组合一个静态字符串和一个变量名来创建一个定义的变量名?

C#中的解析器。如何从字符串填充类

用比较器类创建一个数组