forked from onlyabout/spring-data-rest-client
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
1. add support for polymorphic type handling
2. 0-indexed paging which Spring Data use
- Loading branch information
Showing
11 changed files
with
404 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
74 changes: 74 additions & 0 deletions
74
.../springframework/data/rest/client/json/JacksonPolymorphicDeserializationPreProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package net.daum.clix.springframework.data.rest.client.json; | ||
|
||
import java.lang.reflect.Modifier; | ||
|
||
import net.daum.clix.springframework.data.rest.client.repository.RestRepositories; | ||
|
||
import org.springframework.hateoas.Link; | ||
import org.springframework.util.Assert; | ||
import org.springframework.util.StringUtils; | ||
|
||
import com.google.gson.JsonArray; | ||
import com.google.gson.JsonElement; | ||
import com.google.gson.JsonObject; | ||
import com.google.gson.JsonParser; | ||
|
||
/** | ||
* Used to prepare json before polymorphic deserialization process by adding | ||
* '@class' property to json object. | ||
* | ||
* @author 84june | ||
* | ||
*/ | ||
public class JacksonPolymorphicDeserializationPreProcessor implements JsonPreProcessor { | ||
|
||
private RestRepositories repositories; | ||
|
||
public JacksonPolymorphicDeserializationPreProcessor(RestRepositories repositories) { | ||
Assert.notNull(repositories); | ||
|
||
this.repositories = repositories; | ||
} | ||
|
||
@Override | ||
public boolean canProcess(Class<?> objectType) { | ||
return Modifier.isAbstract(objectType.getModifiers()); | ||
} | ||
|
||
@Override | ||
public byte[] process(byte[] jsonBody, Class<?> resourceType, Class<?> objectType) { | ||
JsonParser parser = new JsonParser(); | ||
JsonObject json = parser.parse(new String(jsonBody)).getAsJsonObject(); | ||
boolean hasMultipleObjects = json.has("content"); | ||
|
||
if (hasMultipleObjects) { | ||
for (JsonElement element : json.get("content").getAsJsonArray()) { | ||
addClassProperty(element.getAsJsonObject()); | ||
} | ||
} else { | ||
addClassProperty(json); | ||
} | ||
|
||
return json.toString().getBytes(); | ||
} | ||
|
||
private void addClassProperty(JsonObject object) { | ||
JsonArray links = object.get("links").getAsJsonArray(); | ||
|
||
for (JsonElement ele : links) { | ||
JsonObject link = ele.getAsJsonObject(); | ||
if (Link.REL_SELF.equals(link.get("rel").getAsString())) { | ||
String resourcePath = getResourcePathFromSelfHref(link.get("href").getAsString()); | ||
String className = repositories.findDomainClassNameFor(resourcePath); | ||
object.addProperty("@class", className); | ||
break; | ||
} | ||
} | ||
} | ||
|
||
private String getResourcePathFromSelfHref(String selfHref) { | ||
String[] tkns = StringUtils.tokenizeToStringArray(selfHref, "/"); | ||
return tkns[tkns.length - 2]; | ||
} | ||
|
||
} |
16 changes: 16 additions & 0 deletions
16
src/main/java/net/daum/clix/springframework/data/rest/client/json/JsonPreProcessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package net.daum.clix.springframework.data.rest.client.json; | ||
|
||
|
||
/** | ||
* Used to prepare json body before (de)serialization process. | ||
* | ||
* @author 84june | ||
* | ||
*/ | ||
public interface JsonPreProcessor { | ||
|
||
boolean canProcess(Class<?> objectType); | ||
|
||
byte[] process(byte[] jsonBody, Class<?> resourceType, Class<?> objectType); | ||
|
||
} |
48 changes: 48 additions & 0 deletions
48
...n/java/net/daum/clix/springframework/data/rest/client/resolver/ConcreateTypeResolver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package net.daum.clix.springframework.data.rest.client.resolver; | ||
|
||
import java.lang.reflect.Modifier; | ||
import java.lang.reflect.Type; | ||
|
||
import net.daum.clix.springframework.data.rest.client.repository.RestRepositories; | ||
|
||
import org.springframework.util.Assert; | ||
|
||
/** | ||
* Resolve concrete type from abstract class by looking up json body. | ||
* | ||
* @author 84june | ||
* | ||
*/ | ||
@Deprecated | ||
public class ConcreateTypeResolver implements TypeResolver { | ||
|
||
@SuppressWarnings("unused") | ||
private RestRepositories repositories; | ||
|
||
public ConcreateTypeResolver(RestRepositories repositories) { | ||
Assert.notNull(repositories); | ||
|
||
this.repositories = repositories; | ||
} | ||
|
||
@Override | ||
public boolean canResolve(Type objectType) { | ||
return Modifier.isAbstract(objectType.getClass().getModifiers()); | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
@Override | ||
public Type resolve(byte[] body, Type typeToResolve) { | ||
String resourcePath = getPathFromSelfHref(body); | ||
|
||
// RepositoryFactoryInformation<Object, Serializable> repoInfo = repositories.findRepositoryInformationFor(resourcePath); | ||
// return repoInfo.getRepositoryInformation().getDomainType(); | ||
throw new IllegalAccessError("ConcreateTypeResolver#resolve has not implemented yet!"); | ||
} | ||
|
||
private String getPathFromSelfHref(byte[] body) { | ||
// TODO Auto-generated method stub | ||
throw new IllegalAccessError("ConcreateTypeResolver#getPathFromSelfHref has not implemented yet!"); | ||
} | ||
|
||
} |
18 changes: 18 additions & 0 deletions
18
src/main/java/net/daum/clix/springframework/data/rest/client/resolver/TypeResolver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package net.daum.clix.springframework.data.rest.client.resolver; | ||
|
||
import java.lang.reflect.Type; | ||
|
||
/** | ||
* Resolve the type of object from json resource body. | ||
* | ||
* @author 84june | ||
* | ||
*/ | ||
@Deprecated | ||
public interface TypeResolver { | ||
|
||
boolean canResolve(Type objectType); | ||
|
||
Type resolve(byte[] body, Type typeToResolve); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
99 changes: 99 additions & 0 deletions
99
...ingframework/data/rest/client/json/JacksonPolymorphicDeserializationPreProcessorTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
package net.daum.clix.springframework.data.rest.client.json; | ||
|
||
import static org.junit.Assert.assertEquals; | ||
import static org.junit.Assert.assertFalse; | ||
import static org.junit.Assert.assertTrue; | ||
import static org.mockito.Mockito.when; | ||
|
||
import java.io.IOException; | ||
import java.util.Arrays; | ||
import java.util.Collection; | ||
import java.util.List; | ||
|
||
import net.daum.clix.springframework.data.rest.client.json.domain.Animal; | ||
import net.daum.clix.springframework.data.rest.client.json.domain.Cat; | ||
import net.daum.clix.springframework.data.rest.client.json.domain.Dog; | ||
import net.daum.clix.springframework.data.rest.client.repository.RestRepositories; | ||
|
||
import org.codehaus.jackson.JsonParseException; | ||
import org.codehaus.jackson.map.JsonMappingException; | ||
import org.codehaus.jackson.map.ObjectMapper; | ||
import org.codehaus.jackson.map.type.TypeFactory; | ||
import org.codehaus.jackson.type.JavaType; | ||
import org.junit.Before; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
import org.mockito.InjectMocks; | ||
import org.mockito.Mock; | ||
import org.mockito.runners.MockitoJUnitRunner; | ||
import org.springframework.hateoas.Link; | ||
import org.springframework.hateoas.PagedResources; | ||
import org.springframework.hateoas.PagedResources.PageMetadata; | ||
import org.springframework.hateoas.Resource; | ||
|
||
@RunWith(MockitoJUnitRunner.class) | ||
public class JacksonPolymorphicDeserializationPreProcessorTest { | ||
|
||
@Mock | ||
RestRepositories repositories; | ||
|
||
@InjectMocks | ||
JacksonPolymorphicDeserializationPreProcessor preProcessor; | ||
|
||
private PagedResources<Resource<Animal>> pagedResources; | ||
|
||
private Resource<Animal> resource; | ||
|
||
@SuppressWarnings("unchecked") | ||
@Before | ||
public void setUp() throws Exception { | ||
Resource<Animal> dog = new Resource<Animal>(new Dog("nameofdog", 1.0), new Link( | ||
"http://anydomainaddr.com/dog/1", "self")); | ||
Resource<Animal> cat = new Resource<Animal>(new Cat("nameofcat", 3), new Link( | ||
"http://anydomainaddr.com/cat/1", "self")); | ||
Resource<Animal> dog2 = new Resource<Animal>(new Dog("nameofdog2", 10.2), new Link( | ||
"http://anydomainaddr.com/dog/2", "self")); | ||
|
||
Collection<Resource<Animal>> animals = Arrays.asList(dog, cat, dog2); | ||
PageMetadata metadata = new PageMetadata(10, 1, 3, 1); | ||
List<Link> asList = Arrays.asList(new Link("http://1.2.3.4/dog/2", "next"), new Link( | ||
"http://1.2.3.4/dog/search", "search")); | ||
|
||
pagedResources = new PagedResources<Resource<Animal>>(animals, metadata, asList); | ||
resource = dog; | ||
|
||
when(repositories.findDomainClassNameFor("dog")).thenReturn(Dog.class.getName()); | ||
when(repositories.findDomainClassNameFor("cat")).thenReturn(Cat.class.getName()); | ||
} | ||
|
||
@Test | ||
public void canProcessPolymorphicTypeOnly() { | ||
assertTrue(preProcessor.canProcess(Animal.class)); | ||
assertFalse(preProcessor.canProcess(Dog.class)); | ||
assertFalse(preProcessor.canProcess(Cat.class)); | ||
} | ||
|
||
@Test | ||
public void processShouldAddClassPropertyProperly() throws JsonParseException, JsonMappingException, IOException { | ||
byte[] processed = preProcessor.process(new ObjectMapper().writeValueAsBytes(resource), Resource.class, Animal.class); | ||
|
||
ObjectMapper mapper = new ObjectMapper(); | ||
JavaType valueType = mapper.getTypeFactory().constructParametricType(Resource.class, Animal.class); | ||
Resource<Animal> processedResource = mapper.readValue(processed, valueType); | ||
|
||
assertEquals(resource, processedResource); | ||
} | ||
|
||
@Test | ||
public void processShouldAddClassPropertyProperlyToResources() throws JsonParseException, JsonMappingException, IOException { | ||
byte[] processed = preProcessor.process(new ObjectMapper().writeValueAsBytes(pagedResources), PagedResources.class, Animal.class); | ||
|
||
ObjectMapper mapper = new ObjectMapper(); | ||
TypeFactory typeFactory = mapper.getTypeFactory(); | ||
JavaType wrappedType = typeFactory.constructParametricType(Resource.class, Animal.class); | ||
JavaType valueType = typeFactory.constructParametricType(PagedResources.class, wrappedType); | ||
PagedResources<Resource<Animal>> processedPagedResources = mapper.readValue(processed, valueType); | ||
|
||
assertEquals(pagedResources, processedPagedResources); | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
src/test/java/net/daum/clix/springframework/data/rest/client/json/domain/Animal.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package net.daum.clix.springframework.data.rest.client.json.domain; | ||
|
||
import org.codehaus.jackson.annotate.JsonTypeInfo; | ||
|
||
@JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class") | ||
public abstract class Animal { | ||
|
||
private String name; | ||
|
||
public Animal() { | ||
} | ||
|
||
public Animal(String name) { | ||
super(); | ||
this.name = name; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public void setName(String name) { | ||
this.name = name; | ||
} | ||
|
||
} |
Oops, something went wrong.