Пока я не предлагаю решение вложенных форм (это не работает надежно), я предоставляю обходной путь, который работает для меня:
Сценарий использования: суперформа, позволяющая изменять N элементов однажды. Он имеет кнопку «Отправить все» внизу. Каждый элемент хочет иметь свою собственную вложенную форму с кнопкой «Отправить элемент № N». Но не может ...
В этом случае можно фактически использовать одну форму, а затем иметь имя кнопок submit_1
.. submit_N
и submitAll
и обрабатывать их на стороне сервера, только глядя на параметры, оканчивающиеся на _1
, если имя кнопки было submit_1
.
<form>
<div id="item1">
<input type="text" name="foo_1" value="23">
<input type="submit" name="submit_1" value="Submit Item #1">
</div>
<div id="item2">
<input type="text" name="foo_2" value="33">
<input type="submit" name="submit_2" value="Submit Item #2">
</div>
<input type="submit" name="submitAll" value="Submit All Items">
</form>
Хорошо, поэтому не так много, но это делает работу.
Если у вас есть возможность добавить библиотеки. Библиотека commons-beanutils может использоваться для обработки bean-компонентов и свойств.
В вашем случае вы могли бы сделать:
Method method = PropertyUtils.getReadMethod( new PropertyDescriptor(key, resultClass));
Может кто-нибудь сказать мне, есть ли альтернативный способ генерации этого метода, который работает как для примитивных, так и для не примитивных типов?
blockquote>Вы не можете этого сделать. У вас не может быть одного объекта метода, который работает для
foo(int)
иfoo(Integer)
. Потому что это будут два разных метода.Причина, по которой компилятор позволяет вам вызывать некоторые
foo(Integer)
с помощьюfoo(5)
, заключается в том, что компилятор использует бокс, чтобы превратить 5 в объект Integer, а затем передать его.Помните: компилятор решает во время компиляции, какой метод будет вызван. Когда есть два метода с одинаковыми именами с разными типами аргументов, это перегрузка ... и происходит во время компиляции.
Короче говоря: либо вы должны создать два объекта метода, либо вы должны предоставить необходимый код для вставки / распаковки между примитивными и упакованными ссылочными типами по мере необходимости!
Вы не объяснили цель этого, но если я вас правильно понимаю, value
является примером значения свойства, и вы хотите использовать его, чтобы узнать тип параметра метода установки.
Но value.getClass()
действительно не подходит для этого, потому что:
value
равно нулю. Итак, некоторые возможные альтернативы:
Предоставить сеттер как лямбда-функцию, вместо попытки взломать вещи с помощью отражения. Это более производительно и более гибко, чем использование отражения.
Если вам нужно использовать отражение, добавьте в код дополнительную переменную Class
, чтобы он знал правильный тип параметра метода установки.
Или, сойти с ума, и взять первый метод, который вы видите, который имеет имя установщика, независимо от его типа:
Method method;
String name = getSetMethod(key);
for (Method m : resultClass.getClass().getMethods()) {
if (m.getName().equals(name)) {
method = m;
break;
}
}
Вам понадобится специальная обработка, чтобы сопоставить эти методы с примитивными параметрами с соответствующими типами в штучной упаковке.
Простой подход, который может быть достаточным, состоит в том, чтобы создать отображение между коробочным и примитивным типами и искать методы, использующие оба типа. Это всего лишь набросок:
Map<Class<?>, Class<?>> boxedToPrimitive = new HashMap<>();
boxedToPrimitive.put(Integer.class, Integer.TYPE);
boxedToPrimitive.put(Long.class, Long.TYPE);
boxedToPrimitive.put(Boolean.class, Boolean.TYPE);
...
String name = getSetMethod(key);
Method method;
try {
method = target.getClass().getMethod(name, val.getClass());
} catch (NoSuchMethodException missing) {
Class<?> alt = boxedToPrimitive.get(val.getClass());
if (alt == null) throw missing;
method = target.getClass().getMethod(name, alt);
}
method.invoke(target, value);