在Java运行时调用不同类的最佳方法

时间:2018-09-27 09:35:23

标签: java json reflection runtime

让我们想象一下,我们必须在运行时根据定义从不同的类调用一种方法。例如,我们收到这样的JSON:

{"calculator": "MyClass1", "parameter1": 1.0, "parameter2": 2.0, ... }

MyClass1和更多类可以扩展某些基类或实现某些接口(只是为了能够在运行时枚举它们)。我们必须创建对象,将参数传递给对象,然后调用calculate()方法。

我可以想到两种方法:

  1. switch(calculatorString){案例“ MyClass1”:计算器= new MyClass1(); ...

  2. 使用Java反射

第一种方法确实很愚蠢,因为每次将新的计算器类添加到项目中时都必须更新代码。第二种方法稍好一些,但是IDE无法捕获我们在创建对象和调用方法时发生的任何类型错误。

还有其他方法(可能更好)吗?

2 个答案:

答案 0 :(得分:0)

您也许可以使用Java服务提供商接口:

在此处查看示例:

https://docs.oracle.com/javase/tutorial/sound/SPI-intro.html
https://www.baeldung.com/java-spi

它允许您实现不同的实现/服务(在服务文件中仍需要类名),但不必直接使用反射。

您在META-INF

中定义服务提供商

META-INF / services / com.baeldung.rate.spi.ExchangeRateProvider

您的服务可以注册自己,如果允许它们使用输入的json,您将非常灵活。

答案 1 :(得分:0)

反射是在运行时创建对象的最佳方法,但其全部取决于用例。 您还可以将工厂设计模式用于对象创建。

使用ReflectionAPI

try {
            cls = Class.forName(className);
            instance = cls.newInstance();
            instance = BeanUtils.populateBean(properties, cls);
} catch (Exception e) {
     e.printStackTrace();           
}

BeanUtil类

public static Object populateBean(Map<String, Object> propertyMap, Class<?> clazz) throws Exception {
    PropertyUtilsBean bean = new PropertyUtilsBean();
    Object obj = null;
    try {
        obj = clazz.newInstance();

        for(Map.Entry<String, Object> entrySet: propertyMap.entrySet()) {
            PropertyDescriptor descriptor = null;
            try {
                descriptor =
                        bean.getPropertyDescriptor(obj, entrySet.getKey());

                if (descriptor == null) {
                    continue;
                }
                Method writeMethod = bean.getWriteMethod(descriptor);
                writeMethod.invoke(obj, convert(descriptor.getPropertyType(), entrySet.getValue(), DATE_PATTERN));

            } catch (IncompatibleConversion e) {
                throw e;
            } catch (Exception e) {
                throw new Exception("Unable to parse");
            }
        }

    }catch(Exception e) {
        throw e;
    }

    return obj;
}

转换班级

private static Object convert(Class<?> clzz, Object value, String datePattern) throws Exception {

    if (clzz.isAssignableFrom(BigInteger.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof BigInteger) {
            return value;
        }

        try {
            return new BigInteger(value.toString());
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(BigDecimal.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof BigDecimal) {
            return parseBigDecimal(value.toString(), DECIMAL_PRECISION);
        }

        try {
            return parseBigDecimal(value.toString(), DECIMAL_PRECISION);
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(Integer.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof Integer) {
            return value;
        }

        try {
            return new Integer(value.toString());
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(Long.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof Long) {
            return value;
        }

        try {
            return new Long(value.toString());
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(String.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof String) {
            return value;
        }

        try {
            return value.toString();
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(Date.class)) {

        if (value == null) {
            return value;
        }

        if (value instanceof Date) {
            return value;
        }

        if (datePattern == null) {
            throw new Exception("date pattern cannot be null");
        }
        try {

            SimpleDateFormat sdf = new SimpleDateFormat(datePattern);
            return sdf.parse(value.toString());
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(Byte.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof Byte) {
            return (value);
        } else if (value instanceof Number) {
            return new Byte(((Number) value).byteValue());
        }

        try {
            return (new Byte(value.toString()));
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(Float.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof Float) {
            return (value);
        }

        try {
            return new Float(value.toString());
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    } else if (clzz.isAssignableFrom(Double.class)) {
        if (value == null) {
            return value;
        }

        if (value instanceof Double) {
            return (value);
        }

        try {
            return new Double(value.toString());
        } catch (Exception e) {
            throw new IncompatibleConversion(e);
        }
    }

    throw new Exception("Incompactible Conversion");
}