DATACMNS-164 - Added support for XML/JSON marshaling of Page, Pageable and Sort.
Added XmlTypeAdapter implementations that convert the PageImpl, PageRequest and Sort value objects into a JAXB marshalable object.
This commit is contained in:
@@ -130,6 +130,20 @@
|
||||
<version>${webbeans.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.hateoas</groupId>
|
||||
<artifactId>spring-hateoas</artifactId>
|
||||
<version>${org.springframework.hateoas.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.sun.xml.bind</groupId>
|
||||
<artifactId>jaxb-impl</artifactId>
|
||||
<version>2.2.3U1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2008-2010 the original author or authors.
|
||||
* Copyright 2008-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.domain.jaxb;
|
||||
|
||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
|
||||
import org.springframework.data.domain.Sort.Order;
|
||||
import org.springframework.data.domain.jaxb.SpringDataJaxb.OrderDto;
|
||||
|
||||
/**
|
||||
* XmlAdapter to convert {@link Order} instances into {@link OrderDto}s and vice versa.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class OrderAdapter extends XmlAdapter<OrderDto, Order> {
|
||||
|
||||
public static final OrderAdapter INSTANCE = new OrderAdapter();
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#marshal(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public OrderDto marshal(Order order) throws Exception {
|
||||
|
||||
if (order == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
OrderDto dto = new OrderDto();
|
||||
dto.direction = order.getDirection();
|
||||
dto.property = order.getProperty();
|
||||
return dto;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public Order unmarshal(OrderDto source) throws Exception {
|
||||
return source == null ? null : new Order(source.direction, source.property);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.domain.jaxb;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.jaxb.SpringDataJaxb.PageDto;
|
||||
import org.springframework.hateoas.Link;
|
||||
|
||||
/**
|
||||
* {@link XmlAdapter} to convert {@link Page} instances into {@link PageDto} instances and vice versa.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class PageAdapter extends XmlAdapter<PageDto, Page<Object>> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#marshal(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public PageDto marshal(Page<Object> source) throws Exception {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
PageDto dto = new PageDto();
|
||||
dto.content = source.getContent();
|
||||
dto.add(getLinks(source));
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public Page<Object> unmarshal(PageDto v) throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return additional links that shall be added to the {@link PageDto}.
|
||||
*
|
||||
* @param source the source {@link Page}.
|
||||
* @return
|
||||
*/
|
||||
protected List<Link> getLinks(Page<?> source) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.domain.jaxb;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.jaxb.SpringDataJaxb.OrderDto;
|
||||
import org.springframework.data.domain.jaxb.SpringDataJaxb.PageRequestDto;
|
||||
import org.springframework.data.domain.jaxb.SpringDataJaxb.SortDto;
|
||||
|
||||
/**
|
||||
* {@link XmlAdapter} to convert {@link Pageable} instances int a {@link PageRequestDto} and vice versa.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
class PageableAdapter extends XmlAdapter<PageRequestDto, Pageable> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#marshal(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public PageRequestDto marshal(Pageable request) throws Exception {
|
||||
|
||||
SortDto sortDto = SortAdapter.INSTANCE.marshal(request.getSort());
|
||||
|
||||
PageRequestDto dto = new PageRequestDto();
|
||||
dto.orders = sortDto == null ? Collections.<OrderDto> emptyList() : sortDto.orders;
|
||||
dto.page = request.getPageNumber();
|
||||
dto.size = request.getPageSize();
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public Pageable unmarshal(PageRequestDto v) throws Exception {
|
||||
|
||||
if (v.orders.isEmpty()) {
|
||||
return new PageRequest(v.page, v.size);
|
||||
}
|
||||
|
||||
SortDto sortDto = new SortDto();
|
||||
sortDto.orders = v.orders;
|
||||
Sort sort = SortAdapter.INSTANCE.unmarshal(sortDto);
|
||||
|
||||
return new PageRequest(v.page, v.size, sort);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.springframework.data.domain.jaxb;
|
||||
|
||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.jaxb.SpringDataJaxb.SortDto;
|
||||
|
||||
/**
|
||||
* {@link XmlAdapter} to convert {@link Sort} instances into {@link SortDto} instances and vice versa.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class SortAdapter extends XmlAdapter<SortDto, Sort> {
|
||||
|
||||
public static final SortAdapter INSTANCE = new SortAdapter();
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#marshal(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public SortDto marshal(Sort source) throws Exception {
|
||||
|
||||
if (source == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
SortDto dto = new SortDto();
|
||||
dto.orders = SpringDataJaxb.marshal(source, OrderAdapter.INSTANCE);
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see javax.xml.bind.annotation.adapters.XmlAdapter#unmarshal(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public Sort unmarshal(SortDto source) throws Exception {
|
||||
return source == null ? null : new Sort(SpringDataJaxb.unmarshal(source.orders, OrderAdapter.INSTANCE));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.domain.jaxb;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlAnyElement;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlElementWrapper;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.adapters.XmlAdapter;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.domain.Sort.Order;
|
||||
import org.springframework.hateoas.ResourceSupport;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Helper class containing utility methods to implement JAXB {@link XmlAdapter}s as well as the DTO types to be
|
||||
* marshalled by JAXB.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class SpringDataJaxb {
|
||||
|
||||
public static final String NAMESPACE = "http://www.springframework.org/schema/data/jaxb";
|
||||
|
||||
/**
|
||||
* The DTO for {@link Pageable}s/{@link PageRequest}s.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@XmlRootElement(name = "page-request", namespace = NAMESPACE)
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class PageRequestDto {
|
||||
|
||||
@XmlAttribute
|
||||
int page, size;
|
||||
@XmlElement(name = "order", namespace = NAMESPACE)
|
||||
List<OrderDto> orders = new ArrayList<OrderDto>();
|
||||
}
|
||||
|
||||
/**
|
||||
* The DTO for {@link Sort}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@XmlRootElement(name = "sort", namespace = NAMESPACE)
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class SortDto {
|
||||
|
||||
@XmlElement(name = "order", namespace = SpringDataJaxb.NAMESPACE)
|
||||
List<OrderDto> orders = new ArrayList<OrderDto>();
|
||||
}
|
||||
|
||||
/**
|
||||
* The DTO for {@link Order}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@XmlRootElement(name = "order", namespace = NAMESPACE)
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class OrderDto {
|
||||
|
||||
@XmlAttribute
|
||||
String property;
|
||||
@XmlAttribute
|
||||
Direction direction;
|
||||
}
|
||||
|
||||
/**
|
||||
* The DTO for {@link Page}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
@XmlRootElement(name = "page", namespace = NAMESPACE)
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
public static class PageDto extends ResourceSupport {
|
||||
|
||||
@XmlAnyElement
|
||||
@XmlElementWrapper(name = "content")
|
||||
List<Object> content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmarshals each element of the given {@link Collection} using the given {@link XmlAdapter}.
|
||||
*
|
||||
* @param source
|
||||
* @param adapter must not be {@literal null}.
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static <T, S> List<T> unmarshal(Collection<S> source, XmlAdapter<S, T> adapter) throws Exception {
|
||||
|
||||
Assert.notNull(adapter);
|
||||
|
||||
if (source == null || source.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<T> result = new ArrayList<T>(source.size());
|
||||
for (S element : source) {
|
||||
result.add(adapter.unmarshal(element));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marshals each of the elements of the given {@link Iterable} using the given {@link XmlAdapter}.
|
||||
*
|
||||
* @param source
|
||||
* @param adapter must not be {@literal null}.
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static <T, S> List<S> marshal(Iterable<T> source, XmlAdapter<S, T> adapter) throws Exception {
|
||||
|
||||
Assert.notNull(adapter);
|
||||
|
||||
if (source == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<S> result = new ArrayList<S>();
|
||||
for (T element : source) {
|
||||
result.add(adapter.marshal(element));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Central domain abstractions especially to be used in combination with the {@link org.springframework.data.repository.Repository} abstraction.
|
||||
*
|
||||
* @see org.springframework.data.repository.Repository
|
||||
*/
|
||||
@XmlSchema(xmlns = { @XmlNs(prefix = "sd", namespaceURI = org.springframework.data.domain.jaxb.SpringDataJaxb.NAMESPACE) })
|
||||
@XmlJavaTypeAdapters({
|
||||
@XmlJavaTypeAdapter(value = org.springframework.data.domain.jaxb.PageableAdapter.class, type = Pageable.class),
|
||||
@XmlJavaTypeAdapter(value = org.springframework.data.domain.jaxb.SortAdapter.class, type = Sort.class),
|
||||
@XmlJavaTypeAdapter(value = org.springframework.data.domain.jaxb.PageAdapter.class, type = Page.class) })
|
||||
package org.springframework.data.domain.jaxb;
|
||||
|
||||
import javax.xml.bind.annotation.XmlNs;
|
||||
import javax.xml.bind.annotation.XmlSchema;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapters;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
|
||||
@@ -0,0 +1,240 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<xs:schema targetNamespace="http://www.w3.org/2005/Atom" elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified"
|
||||
xmlns:atom="http://www.w3.org/2005/Atom" xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
This version of the Atom schema is based on version 1.0 of the format specifications,
|
||||
found here http://www.atomenabled.org/developers/syndication/atom-format-spec.php.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="http://www.w3.org/2001/03/xml.xsd" />
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
An Atom document may have two root elements, feed and entry, as defined in section 2.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:element name="feed" type="atom:feedType"/>
|
||||
<xs:element name="entry" type="atom:entryType"/>
|
||||
<xs:complexType name="textType" mixed="true">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The Atom text construct is defined in section 3.1 of the format spec.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:any namespace="http://www.w3.org/1999/xhtml" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="type" >
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:enumeration value="text"/>
|
||||
<xs:enumeration value="html"/>
|
||||
<xs:enumeration value="xhtml"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attributeGroup ref="atom:commonAttributes"/>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="personType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The Atom person construct is defined in section 3.2 of the format spec.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:choice minOccurs="1" maxOccurs="unbounded">
|
||||
<xs:element name="name" type="xs:string" minOccurs="1" maxOccurs="1" />
|
||||
<xs:element name="uri" type="atom:uriType" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="email" type="atom:emailType" minOccurs="0" maxOccurs="1" />
|
||||
<xs:any namespace="##other"/>
|
||||
</xs:choice>
|
||||
<xs:attributeGroup ref="atom:commonAttributes"/>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="emailType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
Schema definition for an email address.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:restriction base="xs:normalizedString">
|
||||
<xs:pattern value="\w+@(\w+\.)+\w+" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="feedType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The Atom feed construct is defined in section 4.1.1 of the format spec.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:choice minOccurs="3" maxOccurs="unbounded">
|
||||
<xs:element name="author" type="atom:personType" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xs:element name="category" type="atom:categoryType" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xs:element name="contributor" type="atom:personType" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xs:element name="generator" type="atom:generatorType" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="icon" type="atom:iconType" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="id" type="atom:idType" minOccurs="1" maxOccurs="1" />
|
||||
<xs:element name="link" type="atom:linkType" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xs:element name="logo" type="atom:logoType" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="rights" type="atom:textType" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="subtitle" type="atom:textType" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="title" type="atom:textType" minOccurs="1" maxOccurs="1" />
|
||||
<xs:element name="updated" type="atom:dateTimeType" minOccurs="1" maxOccurs="1" />
|
||||
<xs:element name="entry" type="atom:entryType" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:choice>
|
||||
<xs:attributeGroup ref="atom:commonAttributes"/>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="entryType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The Atom entry construct is defined in section 4.1.2 of the format spec.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:choice maxOccurs="unbounded">
|
||||
<xs:element name="author" type="atom:personType" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xs:element name="category" type="atom:categoryType" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xs:element name="content" type="atom:contentType" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="contributor" type="atom:personType" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xs:element name="id" type="atom:idType" minOccurs="1" maxOccurs="1" />
|
||||
<xs:element name="link" type="atom:linkType" minOccurs="0" maxOccurs="unbounded" />
|
||||
<xs:element name="published" type="atom:dateTimeType" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="rights" type="atom:textType" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="source" type="atom:textType" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="summary" type="atom:textType" minOccurs="0" maxOccurs="1" />
|
||||
<xs:element name="title" type="atom:textType" minOccurs="1" maxOccurs="1" />
|
||||
<xs:element name="updated" type="atom:dateTimeType" minOccurs="1" maxOccurs="1" />
|
||||
<xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:choice>
|
||||
<xs:attributeGroup ref="atom:commonAttributes"/>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="contentType" mixed="true">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The Atom content construct is defined in section 4.1.3 of the format spec.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:sequence>
|
||||
<xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" />
|
||||
</xs:sequence>
|
||||
<xs:attribute name="type" type="xs:string"/>
|
||||
<xs:attribute name="src" type="xs:anyURI"/>
|
||||
<xs:attributeGroup ref="atom:commonAttributes"/>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="categoryType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The Atom cagegory construct is defined in section 4.2.2 of the format spec.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:attribute name="term" type="xs:string" use="required"/>
|
||||
<xs:attribute name="scheme" type="xs:anyURI" use="optional"/>
|
||||
<xs:attribute name="label" type="xs:string" use="optional"/>
|
||||
<xs:attributeGroup ref="atom:commonAttributes" />
|
||||
</xs:complexType>
|
||||
<xs:complexType name="generatorType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The Atom generator element is defined in section 4.2.4 of the format spec.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:string">
|
||||
<xs:attribute name="uri" use="optional" type="xs:anyURI" />
|
||||
<xs:attribute name="version" use="optional" type="xs:string" />
|
||||
<xs:attributeGroup ref="atom:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="iconType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The Atom icon construct is defined in section 4.2.5 of the format spec.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:anyURI">
|
||||
<xs:attributeGroup ref="atom:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="idType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The Atom id construct is defined in section 4.2.6 of the format spec.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:anyURI">
|
||||
<xs:attributeGroup ref="atom:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="linkType" mixed="true">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The Atom link construct is defined in section 3.4 of the format spec.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:attribute name="href" use="required" type="xs:anyURI" />
|
||||
<xs:attribute name="rel" type="xs:string" use="optional"/>
|
||||
<xs:attribute name="type" use="optional" type="xs:string" />
|
||||
<xs:attribute name="hreflang" use="optional" type="xs:NMTOKEN" />
|
||||
<xs:attribute name="title" use="optional" type="xs:string" />
|
||||
<xs:attribute name="length" use="optional" type="xs:positiveInteger" />
|
||||
<xs:attributeGroup ref="atom:commonAttributes"/>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="logoType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The Atom logo construct is defined in section 4.2.8 of the format spec.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:anyURI">
|
||||
<xs:attributeGroup ref="atom:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="sourceType">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
The Atom source construct is defined in section 4.2.11 of the format spec.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:choice maxOccurs="unbounded">
|
||||
<xs:element name="author" type="atom:personType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="category" type="atom:categoryType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="contributor" type="atom:personType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="generator" type="atom:generatorType" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="icon" type="atom:iconType" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="id" type="atom:idType" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="link" type="atom:linkType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="logo" type="atom:logoType" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="rights" type="atom:textType" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="subtitle" type="atom:textType" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="title" type="atom:textType" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:element name="updated" type="atom:dateTimeType" minOccurs="0" maxOccurs="1"/>
|
||||
<xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:choice>
|
||||
<xs:attributeGroup ref="atom:commonAttributes"/>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="uriType">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:anyURI">
|
||||
<xs:attributeGroup ref="atom:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="dateTimeType">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:dateTime">
|
||||
<xs:attributeGroup ref="atom:commonAttributes"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:attributeGroup name="commonAttributes">
|
||||
<xs:attribute ref="xml:base" />
|
||||
<xs:attribute ref="xml:lang" />
|
||||
<xs:anyAttribute namespace="##other"/>
|
||||
</xs:attributeGroup>
|
||||
</xs:schema>
|
||||
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://www.springframework.org/schema/data/jaxb"
|
||||
xmlns="http://www.springframework.org/schema/data/jaxb"
|
||||
xmlns:atom="http://www.w3.org/2005/Atom"
|
||||
elementFormDefault="qualified">
|
||||
|
||||
<xs:import namespace="http://www.w3.org/2005/Atom" schemaLocation="atom.xsd" />
|
||||
|
||||
<xs:element name="page-request" type="pageRequest" />
|
||||
<xs:element name="page" type="page" />
|
||||
<xs:element name="sort" type="sort" />
|
||||
<xs:element name="order" type="order" />
|
||||
|
||||
<xs:complexType name="pageRequest">
|
||||
<xs:sequence>
|
||||
<xs:element name="order" type="order" minOccurs="0" maxOccurs="unbounded" />
|
||||
</xs:sequence>
|
||||
<xs:attribute name="page" type="xs:integer" use="required" />
|
||||
<xs:attribute name="size" type="xs:integer" use="required" />
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="page">
|
||||
<xs:sequence>
|
||||
<xs:element name="content" minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:complexType>
|
||||
<xs:all />
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="link" type="atom:linkType" minOccurs="0" maxOccurs="unbounded" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="sort">
|
||||
<xs:sequence>
|
||||
<xs:element name="order" type="order" minOccurs="0" maxOccurs="unbounded" />
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:complexType name="order">
|
||||
<xs:attribute name="property" type="xs:string" />
|
||||
<xs:attribute name="direction" type="direction" />
|
||||
</xs:complexType>
|
||||
|
||||
<xs:simpleType name="direction">
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="ASC" />
|
||||
<xs:enumeration value="DESC" />
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
|
||||
</xs:schema>
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.data.domain.jaxb;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.Marshaller;
|
||||
import javax.xml.bind.Unmarshaller;
|
||||
import javax.xml.bind.annotation.XmlAccessType;
|
||||
import javax.xml.bind.annotation.XmlAccessorType;
|
||||
import javax.xml.bind.annotation.XmlAttribute;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlRootElement;
|
||||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.hateoas.Link;
|
||||
|
||||
/**
|
||||
* Unit test for custom JAXB conversions for Spring Data value objects.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class SpringDataJaxbUnitTests {
|
||||
|
||||
Marshaller marshaller;
|
||||
Unmarshaller unmarshaller;
|
||||
|
||||
Sort sort = new Sort(Direction.ASC, "firstname", "lastname");
|
||||
Pageable reference = new PageRequest(2, 15, sort);
|
||||
Resource resource = new ClassPathResource("pageable.xml", this.getClass());
|
||||
Resource schemaFile = new ClassPathResource("spring-data-jaxb.xsd", this.getClass());
|
||||
|
||||
Scanner scanner;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
JAXBContext context = JAXBContext.newInstance("org.springframework.data.domain.jaxb");
|
||||
|
||||
marshaller = context.createMarshaller();
|
||||
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
|
||||
|
||||
unmarshaller = context.createUnmarshaller();
|
||||
|
||||
scanner = new Scanner(resource.getFile());
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
scanner.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usesCustomTypeAdapterForPageRequests() throws Exception {
|
||||
|
||||
StringWriter writer = new StringWriter();
|
||||
Wrapper wrapper = new Wrapper();
|
||||
wrapper.pageable = reference;
|
||||
wrapper.sort = sort;
|
||||
wrapper.pageableWithoutSort = new PageRequest(10, 20);
|
||||
marshaller.marshal(wrapper, writer);
|
||||
|
||||
for (String line : writer.toString().split("\n")) {
|
||||
assertThat(scanner.hasNextLine(), is(true));
|
||||
assertThat(line, is(scanner.nextLine()));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readsPageRequest() throws Exception {
|
||||
|
||||
Object result = unmarshaller.unmarshal(resource.getFile());
|
||||
|
||||
assertThat(result, is(instanceOf(Wrapper.class)));
|
||||
assertThat(((Wrapper) result).pageable, is(reference));
|
||||
assertThat(((Wrapper) result).sort, is(sort));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writesPlainPage() throws Exception {
|
||||
|
||||
PageWrapper wrapper = new PageWrapper();
|
||||
Content content = new Content();
|
||||
content.name = "Foo";
|
||||
wrapper.page = new PageImpl<Content>(Arrays.asList(content));
|
||||
wrapper.pageWithLinks = new PageImpl<Content>(Arrays.asList(content));
|
||||
|
||||
marshaller.marshal(wrapper, new StringWriter());
|
||||
}
|
||||
|
||||
@XmlRootElement
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
static class Wrapper {
|
||||
|
||||
@XmlElement(name = "page-request", namespace = SpringDataJaxb.NAMESPACE)
|
||||
Pageable pageable;
|
||||
|
||||
@XmlElement(name = "page-request-without-sort", namespace = SpringDataJaxb.NAMESPACE)
|
||||
Pageable pageableWithoutSort;
|
||||
|
||||
@XmlElement(name = "sort", namespace = SpringDataJaxb.NAMESPACE)
|
||||
Sort sort;
|
||||
}
|
||||
|
||||
@XmlRootElement(name = "wrapper", namespace = SpringDataJaxb.NAMESPACE)
|
||||
static class PageWrapper {
|
||||
|
||||
Page<Content> page;
|
||||
|
||||
@XmlElement(name = "page-with-links")
|
||||
@XmlJavaTypeAdapter(LinkedPageAdapter.class)
|
||||
Page<Content> pageWithLinks;
|
||||
}
|
||||
|
||||
@XmlRootElement
|
||||
static class Content {
|
||||
|
||||
@XmlAttribute
|
||||
String name;
|
||||
}
|
||||
|
||||
static class LinkedPageAdapter extends PageAdapter {
|
||||
|
||||
@Override
|
||||
protected List<Link> getLinks(Page<?> source) {
|
||||
return Arrays.asList(new Link(Link.REL_NEXT, "next"), new Link(Link.REL_PREVIOUS, "previous"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
SpringDataJaxbUnitTests$Wrapper
|
||||
SpringDataJaxbUnitTests$PageWrapper
|
||||
SpringDataJaxbUnitTests$Content
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<wrapper xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sd="http://www.springframework.org/schema/data/jaxb">
|
||||
<sd:page-request page="2" size="15">
|
||||
<sd:order property="firstname" direction="ASC"/>
|
||||
<sd:order property="lastname" direction="ASC"/>
|
||||
</sd:page-request>
|
||||
<sd:page-request-without-sort page="10" size="20"/>
|
||||
<sd:sort>
|
||||
<sd:order property="firstname" direction="ASC"/>
|
||||
<sd:order property="lastname" direction="ASC"/>
|
||||
</sd:sort>
|
||||
</wrapper>
|
||||
|
||||
@@ -8,6 +8,7 @@ Import-Template:
|
||||
com.mysema.query.*;version="[2.2.0,3.0.0)";resolution:=optional,
|
||||
javax.enterprise.*;version="${cdi.version:[=.=.=,+1.0.0)}";resolution:=optional,
|
||||
javax.inject.*;version="[1.0.0,2.0.0)";resolution:=optional,
|
||||
javax.xml.bind.*;version="0";resolution:=optional,
|
||||
javax.xml.transform.*;version="0";resolution:=optional,
|
||||
org.codehaus.jackson.*;version="${jackson.version:[=.=.=,+1.0.0)}";resolution:=optional,
|
||||
org.springframework.aop.*;version="${org.springframework.version.30:[=.=.=,+1.0.0)}";resolution:=optional,
|
||||
@@ -18,6 +19,7 @@ Import-Template:
|
||||
org.springframework.expression.*;version="${org.springframework.version.30:[=.=.=,+1.0.0)}";resolution:=optional,
|
||||
org.springframework.expression.spel.standard.*;version="${org.springframework.version.30:[=.=.=,+1.0.0)}";resolution:=optional,
|
||||
org.springframework.expression.spel.support.*;version="${org.springframework.version.30:[=.=.=,+1.0.0)}";resolution:=optional,
|
||||
org.springframework.hateoas.*;version="${org.springframework.hateoas.version:[=.=.=,+1.0.0)}";resolution:=optional,
|
||||
org.springframework.oxm.*;version="${org.springframework.version.30:[=.=.=,+1.0.0)}";resolution:=optional,
|
||||
org.springframework.transaction.*;version="${org.springframework.version.30:[=.=.=,+1.0.0)}";resolution:=optional,
|
||||
org.springframework.util.*;version="${org.springframework.version.30:[=.=.=,+1.0.0)}",
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
<org.springframework.version.30>3.0.7.RELEASE</org.springframework.version.30>
|
||||
<org.springframework.version.40>4.0.0.RELEASE</org.springframework.version.40>
|
||||
<org.springframework.version>[${org.springframework.version.30}, ${org.springframework.version.40})</org.springframework.version>
|
||||
<org.springframework.hateoas.version>0.1.0.RELEASE</org.springframework.hateoas.version>
|
||||
<org.hamcrest.version>1.2.1</org.hamcrest.version>
|
||||
<bundlor.failOnWarnings>true</bundlor.failOnWarnings>
|
||||
</properties>
|
||||
|
||||
Reference in New Issue
Block a user