Permalink
Browse files

First cut of work with JPA entities, start returning data.

  • Loading branch information...
1 parent 1de8990 commit 5477d554f9a06163404cac80e834615a5eea369a @jbrisbin jbrisbin committed with jbrisbin Jan 27, 2012
Showing with 674 additions and 130 deletions.
  1. +1 −0 build.gradle
  2. +3 −0 exporter-core/build.gradle
  3. +31 −0 exporter-core/exporter-core.iml
  4. +8 −0 exporter-core/src/main/java/org/springframework/data/services/Handler.java
  5. +4 −2 exporter-core/src/main/java/org/springframework/data/services/Link.java
  6. +33 −0 exporter-core/src/main/java/org/springframework/data/services/SimpleLink.java
  7. +13 −2 exporter-repository/exporter-repository.iml
  8. +128 −0 ...ry/src/main/java/org/springframework/data/services/repository/jpa/JpaEntityLinkAwareResolver.java
  9. +117 −0 ...-repository/src/main/java/org/springframework/data/services/repository/jpa/JpaEntityMetadata.java
  10. +27 −22 .../main/java/org/springframework/data/services/repository/{ → jpa}/JpaRepositoryEntityResolver.java
  11. +1 −1 ...ry/src/main/java/org/springframework/data/services/repository/{ → jpa}/JpaRepositoryMetadata.java
  12. +1 −1 ...ry/src/main/java/org/springframework/data/services/repository/{ → jpa}/JpaRepositoryResolver.java
  13. +0 −74 ...c/test/groovy/org/springframework/data/services/repository/JpaRepositoryEntityResolverSpec.groovy
  14. +116 −0 ...st/groovy/org/springframework/data/services/repository/jpa/JpaRepositoryEntityResolverSpec.groovy
  15. +0 −9 ...repository/src/test/java/org/springframework/data/services/repository/SimpleEntityRepository.java
  16. +18 −3 exporter-repository/src/test/resources/JpaRepositoryEntityResolver-test.xml
  17. +2 −1 exporter-repository/src/test/resources/META-INF/persistence.xml
  18. +18 −0 exporter-web/exporter-web.iml
  19. +39 −3 exporter-web/src/main/java/org/springframework/data/services/web/JsonView.java
  20. +27 −5 ...-web/src/main/java/org/springframework/data/services/web/exporter/ResourceExporterController.java
  21. +20 −4 exporter-web/src/main/webapp/WEB-INF/exporter-servlet.xml
  22. +6 −2 exporter-web/src/main/webapp/WEB-INF/repositories.xml
  23. +3 −0 exporter-web/src/test/java/org/springframework/data/services/web/exporter/test/Person.java
  24. +55 −0 exporter-web/src/test/java/org/springframework/data/services/web/exporter/test/PersonLoader.java
  25. +3 −0 exporter-web/src/test/java/org/springframework/data/services/web/exporter/test/Profile.java
  26. +0 −1 exporter-web/src/test/resources/logback.xml
View
@@ -59,6 +59,7 @@ subprojects {
// Testing
testCompile "org.spockframework:spock-core:$spockVersion"
+ testCompile "org.spockframework:spock-spring:$spockVersion"
testCompile "org.hamcrest:hamcrest-all:1.1"
testCompile "org.springframework:spring-test:$springVersion"
testRuntime "org.springframework:spring-context-support:$springVersion"
@@ -1,3 +1,6 @@
dependencies {
+ // Google Guava
+ compile "com.google.guava:guava:10.0.1"
+
}
@@ -103,6 +103,17 @@
<orderEntry type="module-library" exported="">
<library>
<CLASSES>
+ <root url="jar://$USER_HOME$/.gradle/caches/artifacts-8/filestore/com.google.guava/guava/10.0.1/jar/292c96f9cb18231528cac4b0bf17d28149d14809/guava-10.0.1.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES>
+ <root url="jar://$USER_HOME$/.gradle/caches/artifacts-8/filestore/com.google.guava/guava/10.0.1/source/50c3953eaac12b8067111030ffdb8e44f80f5a79/guava-10.0.1-sources.jar!/" />
+ </SOURCES>
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library" exported="">
+ <library>
+ <CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/artifacts-8/filestore/org.codehaus.groovy/groovy/1.8.4/jar/344c49f07cf37471935d5103b6cbe7c5aaa09445/groovy-1.8.4.jar!/" />
</CLASSES>
<JAVADOC />
@@ -191,6 +202,15 @@
<orderEntry type="module-library" exported="">
<library>
<CLASSES>
+ <root url="jar://$USER_HOME$/.gradle/caches/artifacts-8/filestore/com.google.code.findbugs/jsr305/1.3.9/jar/40719ea6961c0cb6afaeb6a921eaa1f6afd4cfdf/jsr305-1.3.9.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES />
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library" exported="">
+ <library>
+ <CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/artifacts-8/filestore/antlr/antlr/2.7.7/jar/83cd2cd674a217ade95a4bb83a8a14f351f48bd0/antlr-2.7.7.jar!/" />
</CLASSES>
<JAVADOC />
@@ -289,6 +309,17 @@
<orderEntry type="module-library" scope="TEST">
<library>
<CLASSES>
+ <root url="jar://$USER_HOME$/.gradle/caches/artifacts-8/filestore/org.spockframework/spock-spring/0.5-groovy-1.8/jar/6eee91a4dca521ff93ab82175b4b65e66695fd8a/spock-spring-0.5-groovy-1.8.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES>
+ <root url="jar://$USER_HOME$/.gradle/caches/artifacts-8/filestore/org.spockframework/spock-spring/0.5-groovy-1.8/source/40e43ab43fe73d1bce4b110804704f76127b8f1d/spock-spring-0.5-groovy-1.8-sources.jar!/" />
+ </SOURCES>
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library" scope="TEST">
+ <library>
+ <CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/artifacts-8/filestore/org.hamcrest/hamcrest-all/1.1/jar/2ddcad726ed88eab63eb6666c60970db0ac6d44e/hamcrest-all-1.1.jar!/" />
</CLASSES>
<JAVADOC />
@@ -0,0 +1,8 @@
+package org.springframework.data.services;
+
+/**
+ * @author Jon Brisbin <jon@jbrisbin.com>
+ */
+public interface Handler<T> {
+ void handle(T obj);
+}
@@ -7,8 +7,10 @@
*/
public interface Link {
- String type();
+ public static final String LINKS = "_links";
- URI uri();
+ String rel();
+
+ URI href();
}
@@ -0,0 +1,33 @@
+package org.springframework.data.services;
+
+import java.net.URI;
+
+/**
+ * @author Jon Brisbin <jon@jbrisbin.com>
+ */
+public class SimpleLink implements Link {
+
+ private String rel;
+ private URI href;
+
+ public SimpleLink(String rel, URI href) {
+ this.rel = rel;
+ this.href = href;
+ }
+
+ @Override public String rel() {
+ return rel;
+ }
+
+ @Override public URI href() {
+ return href;
+ }
+
+ @Override public String toString() {
+ return "SimpleLink{" +
+ "rel='" + rel + '\'' +
+ ", href=" + href +
+ '}';
+ }
+
+}
@@ -13,10 +13,10 @@
</facet>
<facet type="Spring" name="Spring">
<configuration>
- <fileset id="fileset1" name="My Fileset" removed="false">
+ <fileset id="fileset1" name="JPA" removed="false">
<file>file://$MODULE_DIR$/src/test/resources/JpaRepositoryEntityResolver-test.xml</file>
- <file>file://$MODULE_DIR$/src/test/resources/Resolver-test.xml</file>
</fileset>
+ <fileset id="fileset2" name="Resolver" removed="false" />
</configuration>
</facet>
</component>
@@ -409,6 +409,17 @@
<orderEntry type="module-library" scope="TEST">
<library>
<CLASSES>
+ <root url="jar://$USER_HOME$/.gradle/caches/artifacts-8/filestore/org.spockframework/spock-spring/0.5-groovy-1.8/jar/6eee91a4dca521ff93ab82175b4b65e66695fd8a/spock-spring-0.5-groovy-1.8.jar!/" />
+ </CLASSES>
+ <JAVADOC />
+ <SOURCES>
+ <root url="jar://$USER_HOME$/.gradle/caches/artifacts-8/filestore/org.spockframework/spock-spring/0.5-groovy-1.8/source/40e43ab43fe73d1bce4b110804704f76127b8f1d/spock-spring-0.5-groovy-1.8-sources.jar!/" />
+ </SOURCES>
+ </library>
+ </orderEntry>
+ <orderEntry type="module-library" scope="TEST">
+ <library>
+ <CLASSES>
<root url="jar://$USER_HOME$/.gradle/caches/artifacts-8/filestore/org.hamcrest/hamcrest-all/1.1/jar/2ddcad726ed88eab63eb6666c60970db0ac6d44e/hamcrest-all-1.1.jar!/" />
</CLASSES>
<JAVADOC />
@@ -0,0 +1,128 @@
+package org.springframework.data.services.repository.jpa;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContext;
+import javax.persistence.metamodel.Attribute;
+import javax.persistence.metamodel.EntityType;
+import javax.persistence.metamodel.Metamodel;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.data.repository.core.EntityInformation;
+import org.springframework.data.services.Handler;
+import org.springframework.data.services.Link;
+import org.springframework.data.services.Resolver;
+import org.springframework.data.services.SimpleLink;
+import org.springframework.data.services.util.UriUtils;
+import org.springframework.transaction.TransactionStatus;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.support.TransactionCallback;
+import org.springframework.transaction.support.TransactionTemplate;
+
+/**
+ * @author Jon Brisbin <jon@jbrisbin.com>
+ */
+public class JpaEntityLinkAwareResolver implements Resolver {
+
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ private URI baseUri;
+ private TransactionTemplate transactionTemplate;
+ private EntityManager entityManager;
+ private Metamodel metamodel;
+ private JpaRepositoryMetadata repositoryMetadata;
+ private Cache<EntityType, JpaEntityMetadata> metadataCache = CacheBuilder.newBuilder().
+ build(new CacheLoader<EntityType, JpaEntityMetadata>() {
+ @Override public JpaEntityMetadata load(EntityType key) throws Exception {
+ return new JpaEntityMetadata(key, repositoryMetadata);
+ }
+ });
+
+ public JpaEntityLinkAwareResolver(URI baseUri,
+ JpaRepositoryMetadata repositoryMetadata,
+ TransactionTemplate transactionTemplate) {
+ this.baseUri = baseUri;
+ this.repositoryMetadata = repositoryMetadata;
+ this.transactionTemplate = transactionTemplate;
+ }
+
+ @PersistenceContext
+ public void setEntityManager(EntityManager entityManager) {
+ this.entityManager = entityManager;
+ this.metamodel = entityManager.getMetamodel();
+ }
+
+ @Override public boolean supports(URI uri, Object target) {
+ return null != target && null != metamodel.entity(target.getClass());
+ }
+
+ @SuppressWarnings({"unchecked"})
+ @Override public Object resolve(final URI uri, final Object target) {
+ final Map<String, Object> model = new HashMap<String, Object>();
+ final List<Link> links = new ArrayList<Link>();
+
+ EntityType entityType = metamodel.entity(target.getClass());
+ try {
+ final JpaEntityMetadata metadata = metadataCache.get(entityType);
+ metadata.doWithEmbedded(new Handler<Attribute>() {
+ @Override public void handle(Attribute attr) {
+ String name = attr.getName();
+ Object val = metadata.get(name, target);
+ model.put(name, val);
+ }
+ });
+ metadata.doWithLinked(new Handler<Attribute>() {
+ @Override public void handle(Attribute attr) {
+ final String name = attr.getName();
+ final Object val = metadata.get(name, target);
+ if (attr.isCollection()) {
+ transactionTemplate.execute(new TransactionCallback<Object>() {
+ @Override public Object doInTransaction(TransactionStatus status) {
+ try {
+ for (Object o : (Collection) val) {
+ EntityInformation entityInfo = repositoryMetadata.entityInfoFor(o.getClass());
+ Link l = new SimpleLink(name, UriUtils.merge(uri, new URI(entityInfo.getId(o).toString())));
+ links.add(l);
+ }
+ } catch (URISyntaxException e) {
+ throw new IllegalStateException(e);
+ }
+ return null;
+ }
+ });
+ }
+ }
+ });
+ } catch (ExecutionException e) {
+ throw new IllegalStateException(e);
+ }
+
+ if (links.size() > 0) {
+ model.put(Link.LINKS, links);
+ }
+
+ return model;
+ }
+
+ @SuppressWarnings({"unchecked"})
+ private List<Link> links(Map<String, Object> model) {
+ List<Link> links = (List<Link>) model.get(Link.LINKS);
+ if (null == links) {
+ links = new ArrayList<Link>();
+ model.put(Link.LINKS, links);
+ }
+ return links;
+ }
+
+}
Oops, something went wrong.

0 comments on commit 5477d55

Please sign in to comment.