Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Java [игнор отключен] [закрыт для гостей] / Адаптер для JAXBElement<T> / 14 сообщений из 14, страница 1 из 1
30.11.2016, 11:39
    #39357518
ivanra
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Адаптер для JAXBElement<T>
Можно ли изменить представление элемента JAXBElement<T> во время маршаллинга?
В частности, интересует JAXBElement<Date>, хочется получить значение без "хвоста" (2016-11-30T11:30:05.539+03:00), на приемной стороне понимают значения только до секунды.
Код: xml
1.
<ns2:dateParameter>2016-11-30T11:30:05.539+03:00</ns2:dateParameter>


Использование XmlAdapter<String, Date> в данном случае не помогает. Обертка JAXBElement требуется, поскольку необходимо передавать null значения
Код: xml
1.
<ns2:dateParameter xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
...
Рейтинг: 0 / 0
30.11.2016, 11:45
    #39357523
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Адаптер для JAXBElement<T>
ivanra,

http://stackoverflow.com/questions/11743306/how-to-represent-null-value-as-empty-element-with-jaxb
Не очень понял почему JAXBElement нужен для xsi:nil? JAXB, ведь должен уметь транслировать и обычный null.
...
Рейтинг: 0 / 0
30.11.2016, 11:57
    #39357532
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Адаптер для JAXBElement<T>
ivanra,

Вот ещё интересный хак
http://stackoverflow.com/a/7110001
Я бы попробовал, чтобы адаптер выбросить.
А JAXBElement заменить на аннотацию @XmlElement(required=true, nillable=true)
...
Рейтинг: 0 / 0
30.11.2016, 12:02
    #39357538
ivanra
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Адаптер для JAXBElement<T>
Там еще есть и строковые параметры, которые могут принимать как null, так и пустую строку. Поэтому JAXBElement.
Да и в принципе непонятно, можно ли тут отрефакторить. На уровень выше список параметров выглядит так
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
    @XmlElementRefs({
        @XmlElementRef(name = "dateParameter", namespace = NS, type = JAXBElement.class),
        @XmlElementRef(name = "floatParameter", namespace = NS, type = JAXBElement.class),
        @XmlElementRef(name = "booleanParameter", namespace = NS, type = JAXBElement.class),
        @XmlElementRef(name = "timeInstantParameter", namespace = NS, type = JAXBElement.class),
        @XmlElementRef(name = "emptyParameter", namespace = NS, type = EmptyParameter.class),
        @XmlElementRef(name = "binaryParameter", namespace = NS, type = JAXBElement.class),
        @XmlElementRef(name = "integerParameter", namespace = NS, type = JAXBElement.class),
        @XmlElementRef(name = "stringParameter", namespace = NS, type = JAXBElement.class)
    })
    protected List<Object> items;
...
Рейтинг: 0 / 0
01.12.2016, 19:29
    #39358871
Usman
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Адаптер для JAXBElement<T>
ivanra,
Код: java
1.
2.
3.
@XmlAnyElement 
@XmlMixed
protected List<Object> items;
...
Рейтинг: 0 / 0
01.12.2016, 20:26
    #39358901
Usman
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Адаптер для JAXBElement<T>
Точнее так.ivanra
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
 
    @XmlAnyElement(lax="true")
    @XmlElementRefs({
        @XmlElementRef(name = "dateParameter", namespace = NS, type = JAXBElement.class),
        @XmlElementRef(name = "floatParameter", namespace = NS, type = JAXBElement.class),
        @XmlElementRef(name = "booleanParameter", namespace = NS, type = JAXBElement.class),
        @XmlElementRef(name = "timeInstantParameter", namespace = NS, type = JAXBElement.class),
        @XmlElementRef(name = "emptyParameter", namespace = NS, type = EmptyParameter.class),
        @XmlElementRef(name = "binaryParameter", namespace = NS, type = JAXBElement.class),
        @XmlElementRef(name = "integerParameter", namespace = NS, type = JAXBElement.class),
        @XmlElementRef(name = "stringParameter", namespace = NS, type = JAXBElement.class)
    })
    protected List<Object> items;


Но в этом случае придется вручную реализовывать ObjectFactory.

см. доки http://docs.oracle.com/javaee/5/api/javax/xml/bind/annotation/XmlAnyElement.html Using XmlAnyElement with XmlElementRef

The XmlAnyElement annotation can be used with XmlElementRefs to designate additional elements that can participate in the content tree.

The following schema would produce the following Java class:


<xs:complexType name="foo">
<xs:choice maxOccurs="unbounded" minOccurs="0">
<xs:element name="a" type="xs:int" />
<xs:element name="b" type="xs:int" />
<xs:any namespace="##other" processContents="lax" />
</xs:choice>
</xs:complexType>

class Foo {
@XmlAnyElement(lax="true")
@XmlElementRefs({
@XmlElementRef(name="a", type="JAXBElement.class")
@XmlElementRef(name="b", type="JAXBElement.class")
})
List<Object> others;
}

@XmlRegistry
class ObjectFactory {
...
@XmlElementDecl(name = "a", namespace = "", scope = Foo.class)
JAXBElement<Integer> createFooA( Integer i ) { ... }

@XmlElementDecl(name = "b", namespace = "", scope = Foo.class)
JAXBElement<Integer> createFooB( Integer i ) { ... }

It can unmarshal instances like

<foo xmlns:e="extra">
<a>1</a> // this will unmarshal to a <A HREF="../../../../javax/xml/bind/JAXBElement.html" title="class in javax.xml.bind"><CODE>JAXBElement</CODE></A> instance whose value is 1.
<e:other /> // this will unmarshal to a DOM <A HREF=" http://java.sun.com/j2se/1.5/docs/api/org/w3c/dom/Element.html" title="class or interface in org.w3c.dom"><CODE>Element</CODE></A>.
<b>3</b> // this will unmarshal to a <A HREF="../../../../javax/xml/bind/JAXBElement.html" title="class in javax.xml.bind"><CODE>JAXBElement</CODE></A> instance whose value is 1.
</foo>

...
Рейтинг: 0 / 0
02.12.2016, 11:05
    #39359162
ivanra
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Адаптер для JAXBElement<T>
Usman, не то. Вопрос был про кастомизацию маршаллинга.
Чтобы вместо этого
Код: xml
1.
2.
3.
4.
        <ns2:commandParameters>
            <ns2:binaryParameter>0000000000018892</ns2:binaryParameter>
            <ns2:dateParameter>2016-12-02T09:42:51.124+03:00</ns2:dateParameter>
        </ns2:commandParameters>

передавалось вот это
Код: xml
1.
2.
3.
4.
        <ns2:commandParameters>
            <ns2:binaryParameter>0000000000018892</ns2:binaryParameter>
            <ns2:dateParameter>2016-12-02T09:42:51</ns2:dateParameter>
        </ns2:commandParameters>


Можно ли задействовать адаптеры для типов данных внутри JAXBElement?. Например, есть
Код: java
1.
public class SimpleDateTimeAdapter extends XmlAdapter<String, Date> {...}

но помещение его в package-info не дает эффекта для JAXBElement<Date>, хотя в случае обычных пропертей типа Date всё работает
Код: java
1.
@XmlJavaTypeAdapter(value=SimpleDateTimeAdapter.class,type=Date.class)
...
Рейтинг: 0 / 0
02.12.2016, 11:41
    #39359194
Blazkowicz
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Адаптер для JAXBElement<T>
ivanra,

Так что на Calendar заменить никак?
...
Рейтинг: 0 / 0
02.12.2016, 12:22
    #39359236
ivanra
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Адаптер для JAXBElement<T>
Blazkowiczivanra,
Так что на Calendar заменить никак?Тоже не то
- при маршаллинге всё равно есть миллисекунды (если установить в 0, то будет окончание .000)
- хочется также избавиться от бойлеркода Date <-> XMLGregorianCalendar
...
Рейтинг: 0 / 0
02.12.2016, 13:08
    #39359277
ferc
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Адаптер для JAXBElement<T>
ivanra,

можно так

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
public class TimeFromDateAdapter extends XmlAdapter<XMLGregorianCalendar, Date> {

    public Date unmarshal(XMLGregorianCalendar value){
        Calendar cal = value.toGregorianCalendar();
        Date d = cal.getTime();
        return d;
    }

    public XMLGregorianCalendar marshal(Date value){
        GregorianCalendar cal = new GregorianCalendar();

        cal.setTime(value);

        try{
            XMLGregorianCalendar xmlDate = DatatypeFactory.newInstance().newXMLGregorianCalendarDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH), 0);
            xmlDate.setTimezone(DatatypeConstants.FIELD_UNDEFINED);
            return xmlDate;
        }
        catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }
}
...
Рейтинг: 0 / 0
02.12.2016, 15:41
    #39359415
ivanra
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Адаптер для JAXBElement<T>
ferc, тоже миллисекунды будут. Тут кровавый легаси энтернпрайз, надо только в определенном формате.
Вот 2 возможных решения:
1) Для случаев, когда не надо передавать пустые значения, заменяем JAXBElement<Date> на свою обертку
Код: java
1.
2.
3.
4.
5.
6.
7.
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "dateParameter")
public class DateParameter {
	@XmlValue
	private Date value;
	//getter+setter
}

На уровень выше меняем аннотацию, чтобы указывала на этот класс
Код: java
1.
@XmlElementRef(name = "dateParameter", namespace = NS, type = DateParameter.class)

Всё прозрачно работает, но в этом случае пустые даты будут передаваться как <dateParameter/> без атрибута nil. Дальше остается только надеяться, что на приемной стороне анмаршаллинг пройдет нормально.

2) другой вариант - вместо JAXBElement<Date> использовать JAXBElement<String>, форматируя это всё в слое логики. Ничего хорошего, но для штучных случаев сойдет
...
Рейтинг: 0 / 0
02.12.2016, 18:38
    #39359609
Usman
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Адаптер для JAXBElement<T>
...
Рейтинг: 0 / 0
22.12.2016, 12:34
    #39372772
IHmG
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Адаптер для JAXBElement<T>
ivanraМожно ли изменить представление элемента JAXBElement<T> во время маршаллинга?
что надо гуглить, чтобы понять Ваш вопрос?

Правильно ли я понял? Вы используете jaxb для того, чтобы сформировать xml и во время маршалинга (сохранение объектов в xml) имеете хвост в виде милисекунд?

Что такое JAXBElement<T>? Что значит представление элемента?
Удалось ли как-то задачу уже решить?
...
Рейтинг: 0 / 0
22.12.2016, 15:12
    #39373029
ivanra
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Адаптер для JAXBElement<T>
IHmG, всё выглядело примерно так. Есть некий сервис, в схеме которого написано:
Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
	<xsd:element name="dateParameter" type="xsd:date">
		<xsd:annotation>
			<xsd:documentation>
				An element for passing a date parameter to or from an AppServer Rule (server script).  Uses the format YYYY-MM-DD, e.g. "1978-07-23".
			</xsd:documentation>
		</xsd:annotation>
	</xsd:element>
...
	<xsd:complexType name="parameters">
		<xsd:annotation>
			<xsd:documentation>
				Elements of this type represent an array of zero or more parameters used by an AppServer rule (server script).
			</xsd:documentation>
		</xsd:annotation>
		<xsd:sequence>
			<xsd:choice minOccurs="0" maxOccurs="unbounded">
				<xsd:element ref="binaryParameter"/>
				<xsd:element ref="booleanParameter"/>
				<xsd:element ref="dateParameter"/>
				<xsd:element ref="emptyParameter"/>
				<xsd:element ref="floatParameter"/>
				<xsd:element ref="integerParameter"/>
				<xsd:element ref="stringParameter"/>
				<xsd:element ref="timeInstantParameter"/>
			</xsd:choice>
		</xsd:sequence>
	</xsd:complexType>


Это описание параметров для вызываемых функции. В том числе, параметры могут иметь нулевые значения, и тогда передаются они в таком виде:
Код: xml
1.
<dateParameter nil="true"/>


xjc по этой схеме сгенерировала класс с аннотацией
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
    @XmlElementRefs({
        @XmlElementRef(name = "dateParameter", namespace = NS, type = JAXBElement.class),
        @XmlElementRef(name = "floatParameter", namespace = NS, type = JAXBElement.class),
        @XmlElementRef(name = "booleanParameter", namespace = NS, type = JAXBElement.class),
        @XmlElementRef(name = "timeInstantParameter", namespace = NS, type = JAXBElement.class),
        @XmlElementRef(name = "emptyParameter", namespace = NS, type = EmptyParameter.class),
        @XmlElementRef(name = "binaryParameter", namespace = NS, type = JAXBElement.class),
        @XmlElementRef(name = "integerParameter", namespace = NS, type = JAXBElement.class),
        @XmlElementRef(name = "stringParameter", namespace = NS, type = JAXBElement.class)
    })
    protected List<Object> items;


и дальше встал вопрос, как передавать даты (в комментариях схемы читаем, что это должен быть формат YYYY-MM-DD). Использование адаптера для даты в данном случае не помогает, так как значения обернуты в JAXBElement. Об этом и был вопрос.
Конечным решением для меня стало использование вместо JAXBElement<Date> такого класса
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
@XmlAccessorType(XmlAccessType.PROPERTY)
@XmlRootElement(name = "dateParameter")
public class DateParameter {
	private Date value;
	@XmlValue
	public Date getValue() {
		return value;
	}
	public void setValue(Date value) {
		this.value = value;
	}
	@XmlAttribute(name="nil", namespace="http://www.w3.org/2001/XMLSchema-instance")
	public Boolean getNil() {
		return value==null?Boolean.TRUE:null;
	}
}


Соответственно изменена строчка в аннотации для элемента "dateParameter"
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
    @XmlElementRefs({
        @XmlElementRef(name = "dateParameter", namespace = NS, type = DateParameter.class),
        @XmlElementRef(name = "floatParameter", namespace = NS, type = JAXBElement.class),
        @XmlElementRef(name = "booleanParameter", namespace = NS, type = JAXBElement.class),
        @XmlElementRef(name = "timeInstantParameter", namespace = NS, type = JAXBElement.class),
        @XmlElementRef(name = "emptyParameter", namespace = NS, type = EmptyParameter.class),
        @XmlElementRef(name = "binaryParameter", namespace = NS, type = JAXBElement.class),
        @XmlElementRef(name = "integerParameter", namespace = NS, type = JAXBElement.class),
        @XmlElementRef(name = "stringParameter", namespace = NS, type = JAXBElement.class)
    })
    protected List<Object> items;


В таком виде адаптер для даты работает. Класс простейший:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
public class SimpleDateTimeAdapter extends XmlAdapter<String, Date> {
	private final SimpleDateFormat shortFormat(){return new SimpleDateFormat("yyyy-MM-dd");}
	@Override
	public Date unmarshal(String v) throws Exception {
		if (v.isEmpty()) return null;
		return shortFormat().parse(v);
	}
	@Override
	public String marshal(Date v) throws Exception {
		if (v==null) return null;
		return shortFormat().format(v);
	}
}


Подключаем его сразу ко всему пакету с помощью аннотации в package-info
Код: java
1.
@XmlJavaTypeAdapter(value=SimpleDateTimeAdapter.class,type=Date.class)
...
Рейтинг: 0 / 0
Форумы / Java [игнор отключен] [закрыт для гостей] / Адаптер для JAXBElement<T> / 14 сообщений из 14, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]