Incorporated recent changes to Spring Data Commons and dependent projects that obsoleted the need to manage domain object metadata within Spring Data REST. Required updating to the latest snapshots available for spring-data-commons and spring-data-jpa.

Additional changes include:

* Re-wrote the monolithic Controller into separate controller classes that have a more narrow focus.
* Implemented common functionality as a `HandlerMethodArgumentResolver` rather than as a helper method in a controller class.
* Re-implemented JSONP functionality as an HttpMessageConverter rather than inline within a controller class.
* Updated to Jackson 2 for all JSON handling.
* By relying on spring-data-commons, spring-data-rest now handles all supported Repository types: JPA, MongoDB, and GemFire.

Added support for MongoDB and GemFire repositories by relying on spring-data-commons to provide the metadata rather than maintaining internal metadata information that is store-specific.

Replaced Spock spec tests with JMock unit and integration tests. Started integrating Jetty 8 into the testing so MVC testing can be done against a live server.
This commit is contained in:
Jon Brisbin
2013-01-04 11:13:04 -06:00
parent 269d6f5983
commit 6e4e7da142
242 changed files with 8466 additions and 9335 deletions

View File

@@ -0,0 +1,13 @@
package org.springframework.data.rest.example;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
/**
* @author Jon Brisbin
*/
@Configuration
@ImportResource("classpath:")
public class RestExporterExampleConfig {
}

View File

@@ -0,0 +1,35 @@
package org.springframework.data.rest.example;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.data.rest.config.RepositoryRestConfiguration;
import org.springframework.data.rest.example.jpa.Person;
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
/**
* @author Jon Brisbin
*/
@Configuration
@ImportResource("classpath:META-INF/spring/security-config.xml")
public class RestExporterExampleRestConfig extends RepositoryRestMvcConfiguration {
@Override protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.addResourceMappingForDomainType(Person.class)
.addResourceMappingFor("lastName")
.setPath("surname");
config.addResourceMappingForDomainType(Person.class)
.addResourceMappingFor("siblings")
.setRel("siblings")
.setPath("siblings");
}
// @Bean public ResourceProcessor<Resource<?>> globalResourceProcessor() {
// return new ResourceProcessor<Resource<?>>() {
// @Override public Resource<?> process(Resource<?> resource) {
// resource.add(new Link("href", "rel"));
// return resource;
// }
// };
// }
}

View File

@@ -0,0 +1,49 @@
package org.springframework.data.rest.example;
import java.util.EnumSet;
import javax.servlet.DispatcherType;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import org.springframework.data.rest.example.gemfire.GemfireRepositoryConfig;
import org.springframework.data.rest.example.jpa.JpaRepositoryConfig;
import org.springframework.data.rest.example.mongodb.MongoDbRepositoryConfig;
import org.springframework.data.rest.webmvc.RepositoryRestDispatcherServlet;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.DelegatingFilterProxy;
/**
* @author Jon Brisbin
*/
public class RestExporterWebInitializer implements WebApplicationInitializer {
@Override public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext rootCtx = new AnnotationConfigWebApplicationContext();
rootCtx.register(
JpaRepositoryConfig.class,
MongoDbRepositoryConfig.class,
GemfireRepositoryConfig.class
);
servletContext.addListener(new ContextLoaderListener(rootCtx));
servletContext.addFilter("springSecurity", DelegatingFilterProxy.class);
servletContext.getFilterRegistration("springSecurity").addMappingForUrlPatterns(
EnumSet.of(DispatcherType.REQUEST),
false,
"/*"
);
AnnotationConfigWebApplicationContext webCtx = new AnnotationConfigWebApplicationContext();
webCtx.register(RestExporterExampleRestConfig.class);
RepositoryRestDispatcherServlet dispatcherServlet = new RepositoryRestDispatcherServlet(webCtx);
ServletRegistration.Dynamic reg = servletContext.addServlet("rest-exporter", dispatcherServlet);
reg.setLoadOnStartup(1);
reg.addMapping("/*");
}
}

View File

@@ -0,0 +1,33 @@
/*
* 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.rest.example.gemfire;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.data.gemfire.repository.config.EnableGemfireRepositories;
/**
* Spring JavaConfig configuration class to setup a Spring container and infrastructure components.
*
* @author Oliver Gierke
* @author David Turanski
*/
@Configuration
@ImportResource("classpath:META-INF/spring/cache-config.xml")
@EnableGemfireRepositories
public class GemfireRepositoryConfig {
}

View File

@@ -0,0 +1,77 @@
/*
* 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.rest.example.gemfire.core;
import org.springframework.data.annotation.Id;
/**
* Base class for persistent classes.
*
* @author Oliver Gierke
* @author David Turanski
*/
public class AbstractPersistentEntity {
@Id
private final Long id;
/**
* Returns the identifier of the entity.
*
* @return the id
*/
public Long getId() {
return id;
}
protected AbstractPersistentEntity(Long id) {
this.id = id;
}
protected AbstractPersistentEntity() {
this.id = null;
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (this.id == null || obj == null || !(this.getClass().equals(obj.getClass()))) {
return false;
}
AbstractPersistentEntity that = (AbstractPersistentEntity) obj;
return this.id.equals(that.getId());
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return id == null ? 0 : id.hashCode();
}
}

View File

@@ -0,0 +1,82 @@
/*
* 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.rest.example.gemfire.core;
import org.springframework.util.Assert;
/**
* An address.
*
* @author Oliver Gierke
*/
public class Address {
private final String street, city, country;
/**
* Creates a new {@link Address} from the given street, city and country.
*
* @param street must not be {@literal null} or empty.
* @param city must not be {@literal null} or empty.
* @param country must not be {@literal null} or empty.
*/
public Address(String street, String city, String country) {
Assert.hasText(street, "Street must not be null or empty!");
Assert.hasText(city, "City must not be null or empty!");
Assert.hasText(country, "Country must not be null or empty!");
this.street = street;
this.city = city;
this.country = country;
}
/**
* Returns a copy of the current {@link Address} instance which is a new entity in terms of persistence.
*
* @return
*/
public Address getCopy() {
return new Address(this.street, this.city, this.country);
}
/**
* Returns the street.
*
* @return
*/
public String getStreet() {
return street;
}
/**
* Returns the city.
*
* @return
*/
public String getCity() {
return city;
}
/**
* Returns the country.
*
* @return
*/
public String getCountry() {
return country;
}
}

View File

@@ -0,0 +1,140 @@
/*
* 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.rest.example.gemfire.core;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.data.gemfire.mapping.Region;
import org.springframework.util.Assert;
/**
* A customer.
*
* @author Oliver Gierke
* @author David Turanski
*/
@Region
public class Customer extends AbstractPersistentEntity {
private EmailAddress emailAddress;
private String firstname, lastname;
private Set<Address> addresses = new HashSet<Address>();
/**
* Creates a new {@link Customer} from the given parameters.
*
* @param id
* the unique id;
* @param emailAddress
* must not be {@literal null} or empty.
* @param firstname
* must not be {@literal null} or empty.
* @param lastname
* must not be {@literal null} or empty.
*/
public Customer(Long id, EmailAddress emailAddress, String firstname, String lastname) {
super(id);
Assert.hasText(firstname);
Assert.hasText(lastname);
Assert.notNull(emailAddress);
this.firstname = firstname;
this.lastname = lastname;
this.emailAddress = emailAddress;
}
protected Customer() {
}
/**
* Adds the given {@link Address} to the {@link Customer}.
*
* @param address
* must not be {@literal null}.
*/
public void add(Address address) {
Assert.notNull(address);
this.addresses.add(address);
}
/**
* Returns the firstname of the {@link Customer}.
*
* @return
*/
public String getFirstname() {
return firstname;
}
/**
* Sets the firstname of the {@link Customer}.
*
* @param firstname
*/
public void setFirstname(String firstname) {
this.firstname = firstname;
}
/**
* Returns the lastname of the {@link Customer}.
*
* @return
*/
public String getLastname() {
return lastname;
}
/**
* Sets the lastname of the {@link Customer}.
*
* @param lastname
*/
public void setLastname(String lastname) {
this.lastname = lastname;
}
/**
* Returns the {@link EmailAddress} of the {@link Customer}.
*
* @return
*/
public EmailAddress getEmailAddress() {
return emailAddress;
}
/**
* Sets the emailAddress of the {@link Customer}.
*
* @param emailAddress
*/
public void setEmailAddress(EmailAddress emailAddress) {
this.emailAddress = emailAddress;
}
/**
* Return the {@link Customer}'s addresses.
*
* @return
*/
public Set<Address> getAddresses() {
return Collections.unmodifiableSet(addresses);
}
}

View File

@@ -0,0 +1,50 @@
/*
* 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.rest.example.gemfire.core;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
/**
* Repository interface to access {@link Customer}s.
*
* @author Oliver Gierke
* @author David Turanski
*/
public interface CustomerRepository extends CrudRepository<Customer, Long> {
/**
* Finds all {@link Customer}s with the given lastname.
*
* @param lastname
*
* @return
*/
List<Customer> findByLastname(@Param("lastname") String lastname);
/**
* Finds the Customer with the given {@link EmailAddress}.
*
* @param emailAddress
*
* @return
*/
Customer findByEmailAddress(@Param("email") EmailAddress emailAddress);
}

View File

@@ -0,0 +1,126 @@
/*
* 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.rest.example.gemfire.core;
import java.util.regex.Pattern;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Value object to represent email addresses.
*
* @author Oliver Gierke
*/
@JsonSerialize(using = ToStringSerializer.class)
public final class EmailAddress {
private static final String EMAIL_REGEX = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
private static final Pattern PATTERN = Pattern.compile(EMAIL_REGEX);
private final String value;
/**
* Creates a new {@link EmailAddress} from the given {@link String} representation.
*
* @param emailAddress
* must not be {@literal null} or empty.
*/
@JsonCreator
public EmailAddress(String emailAddress) {
Assert.isTrue(isValid(emailAddress), "Invalid email address!");
this.value = emailAddress;
}
/**
* Returns whether the given {@link String} is a valid {@link EmailAddress} which means you can safely instantiate
* the
* class.
*
* @param candidate
*
* @return
*/
public static boolean isValid(String candidate) {
return candidate == null ? false : PATTERN.matcher(candidate).matches();
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return value;
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if(this == obj) {
return true;
}
if(!(obj instanceof EmailAddress)) {
return false;
}
EmailAddress that = (EmailAddress)obj;
return this.value.equals(that.value);
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return value.hashCode();
}
@Component
static class EmailAddressToStringConverter implements Converter<EmailAddress, String> {
/*
* (non-Javadoc)
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@Override
public String convert(EmailAddress source) {
return source == null ? null : source.value;
}
}
@Component
static class StringToEmailAddressConverter implements Converter<String, EmailAddress> {
/*
* (non-Javadoc)
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
public EmailAddress convert(String source) {
return StringUtils.hasText(source) ? new EmailAddress(source) : null;
}
}
}

View File

@@ -0,0 +1,133 @@
/*
* 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.rest.example.gemfire.core;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.gemfire.mapping.Region;
import org.springframework.util.Assert;
/**
* A product.
*
* @author Oliver Gierke
* @author David Turanski
*/
@Region
public class Product extends AbstractPersistentEntity {
private String name, description;
private BigDecimal price;
private Map<String, String> attributes = new HashMap<String, String>();
/**
* Creates a new {@link Product} with the given name.
*
* @param id
* a unique Id
* @param name
* must not be {@literal null} or empty.
* @param price
* must not be {@literal null} or less than or equal to zero.
*/
public Product(Long id, String name, BigDecimal price) {
this(id, name, price, null);
}
/**
* Creates a new {@link Product} from the given name and description.
*
* @param id
* a unique Id
* @param name
* must not be {@literal null} or empty.
* @param price
* must not be {@literal null} or less than or equal to zero.
* @param description
*/
@PersistenceConstructor
public Product(Long id, String name, BigDecimal price, String description) {
super(id);
Assert.hasText(name, "Name must not be null or empty!");
Assert.isTrue(BigDecimal.ZERO.compareTo(price) < 0, "Price must be greater than zero!");
this.name = name;
this.price = price;
this.description = description;
}
protected Product() {
}
/**
* Sets the attribute with the given name to the given value.
*
* @param name
* must not be {@literal null} or empty.
* @param value
*/
public void setAttribute(String name, String value) {
Assert.hasText(name);
if(value == null) {
this.attributes.remove(value);
} else {
this.attributes.put(name, value);
}
}
/**
* Returns the {@link Product}'s name.
*
* @return
*/
public String getName() {
return name;
}
/**
* Returns the {@link Product}'s description.
*
* @return
*/
public String getDescription() {
return description;
}
/**
* Returns all the custom attributes of the {@link Product}.
*
* @return
*/
public Map<String, String> getAttributes() {
return Collections.unmodifiableMap(attributes);
}
/**
* Returns the price of the {@link Product}.
*
* @return
*/
public BigDecimal getPrice() {
return price;
}
}

View File

@@ -0,0 +1,50 @@
/*
* 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.rest.example.gemfire.core;
import java.util.List;
import org.springframework.data.gemfire.repository.Query;
import org.springframework.data.repository.CrudRepository;
/**
* Repository interface to access {@link Product}s.
*
* @author Oliver Gierke
* @author David TuranskiGem
*/
public interface ProductRepository extends CrudRepository<Product, Long> {
/**
* Returns a list of {@link Product}s having a description which contains the given snippet.
* @param the search string
* @return
*/
List<Product> findByDescriptionContaining(String description);
/**
* Returns all {@link Product}s having the given attribute value.
* @param attribute
* @param value
* @return
*/
@Query("SELECT * FROM /Product where attributes[$1] = $2")
List<Product> findByAttributes(String key, String value);
List<Product> findByName(String name);
}

View File

@@ -0,0 +1,93 @@
/*
* 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.rest.example.gemfire.order;
import java.math.BigDecimal;
import org.springframework.util.Assert;
import org.springframework.data.rest.example.gemfire.core.Product;
/**
* @author Oliver Gierke
*/
public class LineItem {
private BigDecimal price;
private int amount;
private Long productId;
/**
* Creates a new {@link LineItem} for the given {@link Product}.
* @param product must not be {@literal null}.
*/
public LineItem(Product product) {
this(product, 1);
}
/**
* Creates a new {@link LineItem} for the given {@link Product} and amount.
* @param product must not be {@literal null}.
* @param amount
*/
public LineItem(Product product, int amount) {
Assert.notNull(product, "The given Product must not be null!");
Assert.isTrue(amount > 0, "The amount of Products to be bought must be greater than 0!");
this.productId = product.getId();
this.amount = amount;
this.price = product.getPrice();
}
protected LineItem() {
}
/**
* Returns the id of the {@link Product} the {@link LineItem} refers to.
*
* @return
*/
public Long getProductId() {
return productId;
}
/**
* Returns the amount of {@link Product}s to be ordered.
*
* @return
*/
public int getAmount() {
return amount;
}
/**
* Returns the price a single unit of the {@link LineItem}'s product.
*
* @return the price
*/
public BigDecimal getUnitPrice() {
return price;
}
/**
* Returns the total for the {@link LineItem}.
*
* @return
*/
public BigDecimal getTotal() {
return price.multiply(BigDecimal.valueOf(amount));
}
}

View File

@@ -0,0 +1,119 @@
/*
* 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.rest.example.gemfire.order;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.springframework.data.gemfire.mapping.Region;
import org.springframework.data.rest.example.gemfire.core.AbstractPersistentEntity;
import org.springframework.data.rest.example.gemfire.core.Address;
import org.springframework.data.rest.example.gemfire.core.Customer;
import org.springframework.util.Assert;
/**
* @author Oliver Gierke
* @author David Turanski
*/
@Region
public class Order extends AbstractPersistentEntity {
private Long customerId;
private Address billingAddress;
private Address shippingAddress;
private Set<LineItem> lineItems = new HashSet<LineItem>();
/**
* Creates a new {@link Order} for the given {@link Customer}.
*
* @param customer
* must not be {@literal null}.
*/
public Order(Long id, Long customerId, Address shippingAddress) {
super(id);
Assert.notNull(customerId);
Assert.notNull(shippingAddress);
this.customerId = customerId;
this.shippingAddress = shippingAddress;
}
protected Order() {
}
/**
* Adds the given {@link LineItem} to the {@link Order}.
*
* @param lineItem
*/
public void add(LineItem lineItem) {
this.lineItems.add(lineItem);
}
/**
* Returns the id of the {@link Customer} who placed the {@link Order}.
*
* @return
*/
public Long getCustomerId() {
return customerId;
}
/**
* Returns the billing {@link Address} for this order.
*
* @return
*/
public Address getBillingAddress() {
return billingAddress != null ? billingAddress : shippingAddress;
}
/**
* Returns the shipping {@link Address} for this order;
*
* @return
*/
public Address getShippingAddress() {
return shippingAddress;
}
/**
* Returns all {@link LineItem}s currently belonging to the {@link Order}.
*
* @return
*/
public Set<LineItem> getLineItems() {
return Collections.unmodifiableSet(lineItems);
}
/**
* Returns the total of the {@link Order}.
*
* @return
*/
public BigDecimal getTotal() {
BigDecimal total = BigDecimal.ZERO;
for(LineItem item : lineItems) {
total = total.add(item.getTotal());
}
return total;
}
}

View File

@@ -0,0 +1,28 @@
/*
* 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.rest.example.gemfire.order;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
/**
* @author Oliver Gierke
* @author David Turanski
*/
public interface OrderRepository extends CrudRepository<Order, Long> {
List<Order> findByCustomerId(Long customerId);
}

View File

@@ -0,0 +1,60 @@
package org.springframework.data.rest.example.jpa;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.orm.jpa.JpaDialect;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* @author Jon Brisbin
*/
@Configuration
@ComponentScan(basePackageClasses = JpaRepositoryConfig.class)
@EnableJpaRepositories
@EnableTransactionManagement
public class JpaRepositoryConfig {
@Bean public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
@Bean public EntityManagerFactory entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setDatabase(Database.HSQL);
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan(getClass().getPackage().getName());
factory.setDataSource(dataSource());
factory.afterPropertiesSet();
return factory.getObject();
}
@Bean public JpaDialect jpaDialect() {
return new HibernateJpaDialect();
}
@Bean public PlatformTransactionManager transactionManager() {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory());
return txManager;
}
}

View File

@@ -0,0 +1,106 @@
package org.springframework.data.rest.example.jpa;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.PrePersist;
import javax.validation.constraints.NotNull;
import org.springframework.data.rest.repository.annotation.Description;
/**
* An entity that represents a person.
*
* @author Jon Brisbin
*/
@Entity
public class Person {
private Long id;
@Description("A person's first name")
private String firstName;
@Description("A person's last name")
private String lastName;
@Description("A person's siblings")
private List<Person> siblings = Collections.emptyList();
private Person father;
@Description("Timestamp this person object was created")
private Date created;
public Person() {
}
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
@Id @GeneratedValue public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
@NotNull
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Person addSibling(Person p) {
if(siblings == Collections.EMPTY_LIST) {
siblings = new ArrayList<Person>();
}
siblings.add(p);
return this;
}
@ManyToMany public List<Person> getSiblings() {
return siblings;
}
public void setSiblings(List<Person> siblings) {
this.siblings = siblings;
}
@ManyToOne public Person getFather() {
return father;
}
public void setFather(Person father) {
this.father = father;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
}
@PrePersist
private void prePersist() {
this.created = Calendar.getInstance().getTime();
}
}

View File

@@ -0,0 +1,31 @@
package org.springframework.data.rest.example.jpa;
import java.util.Arrays;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author Jon Brisbin
*/
@Component
public class PersonLoader implements InitializingBean {
@Autowired
PersonRepository people;
@Override public void afterPropertiesSet() throws Exception {
Person billyBob = people.save(new Person("Billy Bob", "Thornton"));
Person john = new Person("John", "Doe");
Person jane = new Person("Jane", "Doe");
john.addSibling(jane);
john.setFather(billyBob);
jane.addSibling(john);
jane.setFather(billyBob);
people.save(Arrays.asList(john, jane));
}
}

View File

@@ -0,0 +1,36 @@
package org.springframework.data.rest.example.jpa;
import java.util.Date;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.convert.ISO8601DateConverter;
import org.springframework.data.rest.repository.annotation.ConvertWith;
import org.springframework.data.rest.repository.annotation.RestResource;
/**
* A repository to manage {@link Person}s.
*
* @author Jon Brisbin
*/
@RestResource(rel = "people", path = "people")
public interface PersonRepository extends PagingAndSortingRepository<Person, Long> {
@RestResource(rel = "firstname", path = "firstname")
public Page<Person> findByFirstName(@Param("firstName") String firstName, Pageable pageable);
public Person findFirstPersonByFirstName(@Param("firstName") String firstName);
public Page<Person> findByCreatedGreaterThan(@Param("date") Date date, Pageable pageable);
@Query("select p from Person p where p.created > :date")
public Page<Person> findByCreatedUsingISO8601Date(@Param("date")
@ConvertWith(
ISO8601DateConverter.class)
Date date,
Pageable pageable);
}

View File

@@ -0,0 +1,30 @@
package org.springframework.data.rest.example.mongodb;
import java.net.UnknownHostException;
import com.mongodb.Mongo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
/**
* @author Jon Brisbin
*/
@Configuration
@ComponentScan(basePackageClasses = MongoDbRepositoryConfig.class)
@EnableMongoRepositories
public class MongoDbRepositoryConfig {
@Bean public MongoDbFactory mongoDbFactory() throws UnknownHostException {
return new SimpleMongoDbFactory(new Mongo("localhost"), "spring-data-rest-example");
}
@Bean public MongoTemplate mongoTemplate() throws UnknownHostException {
return new MongoTemplate(mongoDbFactory());
}
}

View File

@@ -0,0 +1,44 @@
package org.springframework.data.rest.example.mongodb;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
/**
* @author Jon Brisbin
*/
@Document
public class Profile {
@Id
private String id;
private Long person;
private String type;
public String getId() {
return id;
}
public Profile setId(String id) {
this.id = id;
return this;
}
public Long getPerson() {
return person;
}
public Profile setPerson(Long person) {
this.person = person;
return this;
}
public String getType() {
return type;
}
public Profile setType(String type) {
this.type = type;
return this;
}
}

View File

@@ -0,0 +1,9 @@
package org.springframework.data.rest.example.mongodb;
import org.springframework.data.repository.CrudRepository;
/**
* @author Jon Brisbin
*/
public interface ProfileRepository extends CrudRepository<Profile, String> {
}

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="jpa.sample">
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
<property name="hibernate.connection.url" value="jdbc:hsqldb:mem:spring"/>
<property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
<property name="hibernate.connection.username" value="sa"/>
<property name="hibernate.connection.password" value=""/>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
</properties>
</persistence-unit>
</persistence>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:gfe="http://www.springframework.org/schema/gemfire"
xsi:schemaLocation="http://www.springframework.org/schema/gemfire http://www.springframework.org/schema/gemfire/spring-gemfire.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<gfe:cache use-bean-factory-locator="false"/>
<gfe:replicated-region id="Customer"/>
<gfe:replicated-region id="Order"/>
<gfe:replicated-region id="Product"/>
</beans>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
</beans>

View File

@@ -0,0 +1,17 @@
<configuration>
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
<logger name="org.springframework.data.rest" level="DEBUG"/>
<root level="INFO">
<appender-ref ref="stdout"/>
</root>
</configuration>