我有一个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,并且我需要该对象的确切形式。我没有主意,如果有人有任何建议,我可以做些阅读。谢谢!
答案 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);
}
}
}