Для начала, я прошу прощения за странный заголовок.Я действительно не знал, как озаглавить это.
У нас есть класс "Factory", который содержит метод для каждого атрибута, который существует в сгенерированных bean-компонентах.Каждый метод класса Factory назван так, чтобы он относился к конкретному классу, содержащему атрибут, и предназначен для создания JAXBElement этого атрибута.К сожалению, этот класс также генерируется автоматически.Это выглядит так:
public class Factory {
private final static QName _MyClassImpl1Attribute1Name_QNAME = new QName("urn:some.urn", "attribute1Name");
private final static QName _MyClassImpl1Attribute2Name_QNAME = new QName("urn:some.urn", "attribute2Name");
private final static QName _MyClassImpl2Attribute1Name_QNAME = new QName("urn:some.urn", "attribute1Name");
private final static QName _MyClassImpl2Attribute2Name_QNAME = new QName("urn:some.urn", "attribute2Name");
/**
* Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}}
*
*/
@XmlElementDecl(namespace = "urn:some.urn", name = "attribute1Name", scope = MyClassImpl1.class)
public JAXBElement<String> createMyClassImpl1Attribute1Name(String value) {
return new JAXBElement<String>(_MyClassImpl1Attribute1Name_QNAME, String.class, MyClassImpl1.class, value);
}
/**
* Create an instance of {@link JAXBElement }{@code <}{@link Boolean}{@code >}}
*
*/
@XmlElementDecl(namespace = "urn:some.urn", name = "attribute2Name", scope = MyClassImpl1.class)
public JAXBElement<Boolean> createMyClassImpl1Attribute2Name(Boolean value) {
return new JAXBElement<Boolean>(_MyClassImpl1Attribute2Name_QNAME, Boolean.class, MyClassImpl1.class, value);
}
/**
* Create an instance of {@link JAXBElement }{@code <}{@link String }{@code >}}
*
*/
@XmlElementDecl(namespace = "urn:some.urn", name = "attribute1Name", scope = MyClassImpl2.class)
public JAXBElement<String> createMyClassImpl2Attribute1Name(String value) {
return new JAXBElement<String>(_MyClassImpl2Attribute1Name_QNAME, String.class, MyClassImpl2.class, value);
}
/**
* Create an instance of {@link JAXBElement }{@code <}{@link Boolean}{@code >}}
*
*/
@XmlElementDecl(namespace = "urn:some.urn", name = "attribute2Name", scope = MyClassImpl2.class)
public JAXBElement<Boolean> createMyClassImpl2Attribute2Name(Boolean value) {
return new JAXBElement<Boolean>(_MyClassImpl2Attribute2Name_QNAME, Boolean.class, MyClassImpl2.class, value);
}
}
Проблема здесь в том, что каждое имя метода соответствует имени класса.Нет метода, который говорит «создать атрибут интерфейса», который позволял бы 1 методу работать для всех реализаций этого интерфейса.Опять же, Factory не может быть изменен.Фактически, единственный класс, который МОЖЕТ быть изменен, - это интерфейс:
public interface MyInterface {
JAXBElement<String> getAttribute1Name;
void setAttribute1Name(String attribute1Value);
JAXBElement<Boolean> getAttribute2Name;
void setAttribute2Name(Boolean attribute2Value);
}
Вот 2 сгенерированных класса (за исключением некоторых тегов xml, которые здесь не должны быть релевантными)
public class MyClassImpl1 implements MyInterface {
private String attribute1Name;
private Boolean attribute2Name;
public JAXBElement<String> getAttribute1Name() {
return attribute1Name;
}
public void setAttribute1Name(JAXBElement<String> value) {
this.attribute2Name = value;
}
public JAXBElement<Boolean> getAttribute2Name() {
return attribute2Name;
}
public void setAttribute2Name(JAXBElement<Boolean> value) {
this.attribute2Name = value;
}
}
public class MyClassImpl2 implements MyInterface {
private String attribute1Name;
private Boolean attribute2Name;
public JAXBElement<String> getAttribute1Name() {
return attribute1Name;
}
public void setAttribute1Name(JAXBElement<String> value) {
this.attribute2Name = value;
}
public JAXBElement<Boolean> getAttribute2Name() {
return attribute2Name;
}
public void setAttribute2Name(JAXBElement<Boolean> value) {
this.attribute2Name = value;
}
}
Проблема возникает, когда я выполняю интерфейсный вызов для установщика, потому что фабрика не знает, какой метод (имя конкретного класса) вызывать.
public class AnotherClass {
public void anotherMethod(MyInterface myInterface) {
Factory factory = new Factory();
String value1 = "Some String Value";
Boolean value2 = true;
myInterface.setAttribute1Name(factory.<I need correct method here>(value1));
myInterface.setAttribute2Name(factory.<I need correct method here>(value2));
}
}
Я мог бы сделать это с помощью отраженияНо я не слишком хорош в этом, и, честно говоря, мне не нравится это делать.Но вот что-то, что может работать.Помещение этого в MyInterface:
default JAXBElement getClassImplJaxbElement(Object attributeValue, String attributeToSet, Factory factory) {
String factoryMethodName = "create" + this.getClass().getName() + attributeToSet;
Expression attributeGetter = new Expression(factory, factoryMethodName, new Object[]{attributeValue});
try {
attributeGetter.execute();
return (JAXBElement) attributeGetter.getValue();
} catch (Exception e) {
throw new MyRuntimeException(String.format("Failed to create JAXBElement for attribute '%s' and value '%s'.", attributeToSet, attributeValue), e);
}
}
Что особенно отстойно, так это то, что мне придется вызывать этот новый метод везде, где я хочу вызывать установщик на интерфейсе, что означает медленное отражение каждый раз.Кто-нибудь знает способ сделать это?Опять же, не может изменить ClassImpls и не может изменить Factory.
Классы создаются с помощью файлов .xsd и плагина maven maven-jaxb22-plugin.Я могу создать класс, который реализует интерфейс, добавив плагин jaxb2-basics.