Наличие методов вызова класса утилит интерфейса, когда имена методов класса утилит соответствуют каждой реализации класса вместо интерфейса - PullRequest
0 голосов
/ 07 сентября 2018

Для начала, я прошу прощения за странный заголовок.Я действительно не знал, как озаглавить это.

У нас есть класс "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.

...