从HashMap中提取数据并设置为对象中的属性

时间:2019-03-05 18:45:12

标签: java hashmap

我有一个HashMap,其中包含约500个键值对。这些值将设置为对象的属性,所述对象的示例如下-

public class SomeClass {
    private String attrib1;
    private double attrib2 = Double.NaN
    //getters and setters
}

我必须基于常量从HashMap中提取值,然后将其设置到此对象中。现在,这就是我的做法

public void someMethod(HashMap<String, String> mapToUse, SomeClass some) {
    some.setAttrib1(mapToUse.get(MyConstant.SOME_CONST));
    some.setAttrib2(methodToParseDouble(mapToUse.get(MyConstant.SOME_CONST2)));
}

此代码可以正常工作,没有任何问题,但就我而言,我在Map中有500个键值对,并且该对象包含大约280个属性。因此,具有280个硬编码设置器的代码看起来很丑陋。有没有更好的优雅方法来做到这一点?

现在,我的代码有280个setter方法,对于每个方法,我都有280个键(定义为常量),这些键用于查找属性。

我阅读了有关BeanUtils的文章,但是我正在努力使其与HashMap一起使用。如果你们中有人有一个示例代码,可以用来从HashMap中进行提取和设置,那就太好了。

编辑:

所以我让BeanUtils工作了,但是现在我又遇到了另一个问题。 BeanUtils工作代码

    testMap.put("attrib1", "2");
    testMap.put("attrib2", "3");
    testMap.put("completelyDiffAttrib1", "10000");   //This breaks the code
    SomeClass testBean = new SomeClass();

    BeanUtils.populate(testBean, testMap);

当我在对象中具有Map中提到的所有属性时,上面的代码有效,但是如果我在HashMap中具有额外的值(该类中没有作为属性出现),则代码会中断。我收到NoClassDef发现错误-

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/collections/FastHashMap
Caused by: java.lang.ClassNotFoundException: org.apache.commons.collections.FastHashMap

我已将commons-collections4-4.3.jar添加到类路径中,这在其他地方已提到。

我可以想到一种方法,我可以先过滤掉地图,然后通过填充来运行它,但是我正在寻找更好的方法来实现它。


我无法更改源的方式,即它将成为HashMap,并且我需要该对象的确切形式。我没有主意,如果有人有任何建议,我可以做些阅读。谢谢!

2 个答案:

答案 0 :(得分:1)

起点可能是

static final Map<Class<?>, Function<String, Object>> FUNCTION_MAP = new HashMap<>();

static {
    FUNCTION_MAP.put(String.class, s -> s);
    FUNCTION_MAP.put(Float.class, s -> Float.parseFloat(s));
    FUNCTION_MAP.put(Double.class, s -> methodToParseDouble(s));
}

static void someMethod(
        final Map<String, String> mapToUse,
        final SomeClass some
) throws InvocationTargetException, IllegalAccessException {
    // Extract all the methods of SomeClass
    final Method[] methods = some.getClass().getDeclaredMethods();

    for (final Method method : methods) {
        // Consider only methods which are public (setters)
        if (!Modifier.isPublic(method.getModifiers())) {
            continue;
        }

        final String name = method.getName();

        // Check if it is a setter or not
        if (!name.startsWith("set")) {
            continue;
        }

        // Extract the name of the attribute to set (e.g. setAttrib1 -> Attrib1)
        final String[] key = name.split("set");

        // Extract the single argument type of the setter (String, Double, Float, etc.)
        final Class<?> parameterType = method.getParameterTypes()[0];

        // Select the right converter (specified inside FUNCTION_MAP) for the argument type
        final Function<String, Object> converter = FUNCTION_MAP.get(parameterType);

        // Invoke the method, applying the converter on the Map value associated
        // to the attribute name (e.g. key[1] = Attrib1)
        method.invoke(some, converter.apply(mapToUse.get(key[1])));
    }
}

这不需要外部依赖性。

答案 1 :(得分:1)

使用反射。

以下是使用反射的次佳示例解决方案:

public class Main
{
  public static class BlammyOne
  {
    private String propertyDuece;
    private String propertyTree;
    private String propertyUno;

    public String getPropertyDuece()
    {
      return propertyDuece;
    }

    public String getPropertyTree()
    {
      return propertyTree;
    }

    public String getPropertyUno()
    {
      return propertyUno;
    }

    public void setPropertyDuece(
      final String newValue)
    {
      propertyDuece = newValue;
    }

    public void setPropertyTree(
      final String newValue)
    {
      propertyTree = newValue;
    }

    public void setPropertyUno(
      final String newValue)
    {
      propertyUno = newValue;
    }

    @Override
    public String toString()
    {
      final StringBuilder builder = new StringBuilder();

      builder.append("Uno: ");
      builder.append(propertyUno);
      builder.append(", Duece: ");
      builder.append(propertyDuece);
      builder.append(", Tree: ");
      builder.append(propertyTree);

      return builder.toString();
    }
  }

  public static class BlammyTwo
  {
    private String propertyFive;
    private String propertyFour;
    private String propertyUno;

    public String getPropertyFive()
    {
      return propertyFive;
    }

    public String getPropertyFour()
    {
      return propertyFour;
    }

    public String getPropertyUno()
    {
      return propertyUno;
    }

    public void setPropertyFive(
      final String newValue)
    {
      propertyFive = newValue;
    }

    public void setPropertyFour(
      final String newValue)
    {
      propertyFour = newValue;
    }

    public void setPropertyUno(
      final String newValue)
    {
      propertyUno = newValue;
    }

    @Override
    public String toString()
    {
      final StringBuilder builder = new StringBuilder();

      builder.append("Uno: ");
      builder.append(propertyUno);
      builder.append(", Four: ");
      builder.append(propertyFour);
      builder.append(", Five: ");
      builder.append(propertyFive);

      return builder.toString();
    }
  }

  public static void main(
    final String[] arguments)
  {
    final Map<String, String> valueMap = new HashMap<>();
    final BlammyOne blammyOne = new BlammyOne();
    final BlammyTwo blammyTwo = new BlammyTwo();

    valueMap.put("propertyUno",
      "valueUno");
    valueMap.put("propertyDuece",
      "valueDuece");
    valueMap.put("propertyTree",
      "valueTree");
    valueMap.put("propertyFour",
      "valueFour");
    valueMap.put("propertyFive",
      "valueFive");

    settyBetty(valueMap,
      blammyOne);
    settyBetty(valueMap,
      blammyTwo);

    System.out.println("blammyOne: " + blammyOne);
    System.out.println("blammyTwo: " + blammyTwo);
  }

  private static void settyBetty(
    final Map<String, String> valueMap,
    final Object target)
  {
    final java.lang.reflect.Field[] declaredFieldsArray;

    try
    {
      declaredFieldsArray = target.getClass().getDeclaredFields();

      for (java.lang.reflect.Field currentField : declaredFieldsArray)
      {
        final String fieldValue = currentField.getName();
        final PropertyDescriptor propertyDescriptor;
        final java.lang.reflect.Method writeMethod;

        propertyDescriptor = new PropertyDescriptor(
          currentField.getName(),
          target.getClass());

        writeMethod = propertyDescriptor.getWriteMethod();

        writeMethod.invoke(target,
          fieldValue);
      }
    }
    catch (final SecurityException exception)
    {
      System.out.println("SecurityException: " + exception);
    }
    catch (final IntrospectionException exception)
    {
      System.out.println("IntrospectionException: " + exception);
    }
    catch (IllegalAccessException exception)
    {
      System.out.println("IllegalAccessException: " + exception);
    }
    catch (IllegalArgumentException exception)
    {
      System.out.println("IllegalArgumentException: " + exception);
    }
    catch (InvocationTargetException exception)
    {
      System.out.println("InvocationTargetException: " + exception);
    }
  }
}