使用字符串输入解析自定义对象

时间:2015-01-04 18:28:38

标签: java parsing reflection override

我想解析具有输入值的对象。该对象具有子类。

当我想解析字符串时,我不想创建实例。 但我想覆盖方法'parse'。

class A {
  public A(object param) {
   //code
  }
  public A parse(String input) {
   //code
  }
}

class B extends A {
  public B parse(String input) {
   //code
  }
}

当我解析我想要的对象时,用反射来做:

A newObject =  Class.forName(className).getMethod("parse", myParseText);

有没有一种很好的方法可以做到这一点。

1 个答案:

答案 0 :(得分:0)

为了获得最大的灵活性,我将解析代码移到单独的解析器类中。以下代码是我自己在项目中使用的解析器类的简化实现:

public final class ParseUtil {

    public interface IStringParser<E> {
        public E parse(String s) throws ParseException;
    }

    private ParseUtil() {}

    private static Map<Class<?>, IStringParser<?>> STRING_PARSERS = new ConcurrentHashMap<>();

    public static <E> void registerStringParser(Class<E> c, IStringParser<E> p){
        STRING_PARSERS.put(c, p);
    }

    @SuppressWarnings("unchecked")
    public static <E> IStringParser<E> getStringParser(Class<E> c){
        return (IStringParser<E>) STRING_PARSERS.get(c);
    }

    public static <E> E parse(String s, Class<E> clazz) throws ParseException{
        if (s == null || s.length() == 0 || clazz == null) {
            throw new IllegalArgumentException();
        }

        IStringParser<E> stringParser = getStringParser(clazz);
        if (stringParser == null) {
            throw new ParseException(clazz);
        }
        return stringParser.parse(s);
    }
}

然后可以将IStringParser任意类的ParserUtil实现注册到ParseUtil.registerStringParser(File.class, new IStringParser<File>() { @Override public File parse(String s)throws ParseException { return new File(s); } }); ,如下所示:

ParseUtil.registerStringParser(File.class, s -> new File(s));

或使用lambda:IStringParser

调用者有责任决定如何解析一个类以及IStringParser何时注册/未注册。

通过将解析代码从类本身移开,以后只需注册不同的parse或更改ParseUtil类的IStringParser方法,就可以轻松更改实现。例如,在我自己的项目中,我使用以下parse方法为已知的Java类提供一些合理的默认值,并使用Gson来解析没有注册其他public static <E> E parse(String s, Class<E> clazz) throws ParseException{ if (s == null || s.length() == 0 || clazz == null) { throw new IllegalArgumentException(); } IStringParser<E> stringParser = getStringParser(clazz); if (stringParser != null) { return stringParser.parse(s); } if (Number.class.isAssignableFrom(clazz)) { // simple number try { if (clazz == Integer.class) { return clazz.cast(Integer.parseInt(s)); } if (clazz == Long.class) { return clazz.cast(Long.parseLong(s)); } if (clazz == Double.class) { return clazz.cast(Double.parseDouble(s)); } if (clazz == Float.class) { return clazz.cast(Float.parseFloat(s)); } if (clazz == Short.class) { return clazz.cast(Short.parseShort(s)); } if (clazz == Byte.class) { return clazz.cast(Byte.parseByte(s)); } } catch (NumberFormatException e) { throw new ParseException(clazz, e); } } if (clazz == String.class) { return clazz.cast(s); } if (clazz == Character.class) { if (s.length() == 1) { return clazz.cast(s.charAt(0)); } else{ throw new ParseException("Unable to parse Character \"" + s + "\""); } } if (clazz == Boolean.class) { switch (s) { case "true": return clazz.cast(Boolean.TRUE); case "false": return clazz.cast(Boolean.FALSE); case "1": return clazz.cast(Boolean.TRUE); case "0": return clazz.cast(Boolean.FALSE); default: throw new ParseException("Unable to parse boolean \"" + s + "\""); } } if (clazz == Class.class) { try { return clazz.cast(Class.forName(s)); } catch (ClassNotFoundException e) { throw new ParseException(clazz, e); } } if (Enum.class.isAssignableFrom(clazz)) { @SuppressWarnings({ "rawtypes" }) Class c = (Class)clazz; @SuppressWarnings("unchecked") Object o = Enum.valueOf(c, s); return clazz.cast(o); } E result = null; try { // if all else fails use Gson to parse the class result = getGSON().fromJson(s, clazz); } catch (JsonSyntaxException e) { throw new ParseException(clazz. e); } if (result == null) { throw new ParseException(clazz); } return result; } 的对象:

{{1}}