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

问题描述 投票:-1回答:2

我有一个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个硬编码的setter看起来很难看。有更好的方式来做到这一点吗?

现在我的代码有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);

上面的代码在我拥有我的Object中的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添加到类路径中,这在别处提到过。

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


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

java hashmap
2个回答
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
投票

使用反射。

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

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);
    }
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.