Created a generalized key-value store,MetaDataMap, for a map of MetaData.

Moved MetaData to wsdef from wsf.
Added a Gson type adapter for Id type.
This commit is contained in:
Inderjeet Singh 2010-10-18 15:45:35 +00:00
parent 8cbdd8a030
commit 281ed6f866
6 changed files with 317 additions and 16 deletions

View File

@ -0,0 +1,101 @@
/*
* Copyright (C) 2010 Google Inc.
*
* 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 com.google.gson.webservice.definition.rest;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.gson.reflect.TypeToken;
/**
* Metadata associated with a repository for a rest resource
*
* @author inder
*
* @param <R> The resource
*/
public final class MetaData<R extends RestResource<R>> {
private final Map<String, String> map;
public static <RS extends RestResource<RS>> MetaData<RS> create() {
return new MetaData<RS>();
}
@SuppressWarnings({"unchecked", "rawtypes"})
private static MetaData<?> createTypeUnsafe(Map<String, String> values) {
return new MetaData(values);
}
public MetaData() {
this(new HashMap<String, String>());
}
private MetaData(Map<String, String> values) {
this.map = values;
}
public String getString(String key) {
return (String) map.get(key);
}
public void putString(String key, String value) {
map.put(key, value);
}
public boolean getBoolean(String key) {
String value = map.get(key);
return value == null ? false : Boolean.parseBoolean(value);
}
public void putBoolean(String key, boolean value) {
map.put(key, String.valueOf(value));
}
public void remove(String key) {
map.remove(key);
}
/**
* Gson Type adapter for {@link MetaData}. The serialized representation on wire is just a
* Map<String, String>
*/
public static final class GsonTypeAdapter implements JsonSerializer<MetaData<?>>,
JsonDeserializer<MetaData<?>>{
private static final Type MAP_TYPE = new TypeToken<Map<String, String>>(){}.getType();
@Override
public MetaData<?> deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
Map<String, String> map = context.deserialize(json, MAP_TYPE);
return MetaData.createTypeUnsafe(map);
}
@Override
public JsonElement serialize(MetaData<?> src, Type typeOfSrc,
JsonSerializationContext context) {
return context.serialize(src.map, MAP_TYPE);
}
}
}

View File

@ -23,5 +23,4 @@ package com.google.gson.webservice.definition.rest;
* @param <R> the rest resource type
*/
public interface RestResource<R> extends HasId<R> {
}

View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2010 Google Inc.
*
* 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 com.google.gson.webservice.typeadapters;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.gson.webservice.definition.rest.Id;
/**
* Type adapter for converting an Id to its serialized form
*
* @author inder
*
*/
public final class IdTypeAdapter implements JsonSerializer<Id<?>>, JsonDeserializer<Id<?>> {
@Override
public JsonElement serialize(Id<?> src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.getValue());
}
@Override
public Id<?> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
if (!(typeOfT instanceof ParameterizedType)) {
throw new JsonParseException("Id of unknown type: " + typeOfT);
}
ParameterizedType parameterizedType = (ParameterizedType) typeOfT;
// Since Id takes only one TypeVariable, the actual type corresponding to the first
// TypeVariable is the Type we are looking for
Type typeOfId = parameterizedType.getActualTypeArguments()[0];
return Id.get(json.getAsLong(), typeOfId);
}
}

View File

@ -0,0 +1,134 @@
/*
* Copyright (C) 2010 Google Inc.
*
* 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 com.google.gson.webservice.typeadapters;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import junit.framework.TestCase;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.google.gson.webservice.definition.rest.Id;
/**
* Unit tests for {@link IdTypeAdapter}
*
* @author inder
*/
public class IdTypeAdapterTest extends TestCase {
private static final Id<Student> STUDENT1_ID = Id.get(5L, Student.class);
private static final Id<Student> STUDENT2_ID = Id.get(6L, Student.class);
private static final Student STUDENT1 = new Student(STUDENT1_ID, "first");
private static final Student STUDENT2 = new Student(STUDENT2_ID, "second");
private static final Type TYPE_COURSE_HISTORY =
new TypeToken<Course<HistoryCourse>>(){}.getType();
private static final Id<Course<HistoryCourse>> COURSE_ID = Id.get(10L, TYPE_COURSE_HISTORY);
private Gson gson;
private Course<HistoryCourse> course;
@Override
protected void setUp() {
gson = new GsonBuilder()
.registerTypeAdapter(Id.class, new IdTypeAdapter())
.create();
course = new Course<HistoryCourse>(COURSE_ID, 4,
new Assignment<HistoryCourse>(null, null), createList(STUDENT1, STUDENT2));
}
public void testSerializeId() {
String json = gson.toJson(course, TYPE_COURSE_HISTORY);
System.out.println(json);
assertTrue(json.contains(String.valueOf(COURSE_ID.getValue())));
assertTrue(json.contains(String.valueOf(STUDENT1_ID.getValue())));
assertTrue(json.contains(String.valueOf(STUDENT2_ID.getValue())));
}
public void testDeserializeId() {
String json = "{courseId:1,students:[{id:1,name:'first'},{id:6,name:'second'}],"
+ "numAssignments:4,assignment:{}}";
Course<HistoryCourse> target = gson.fromJson(json, TYPE_COURSE_HISTORY);
assertEquals(1, target.getStudents().get(0).id.getValue());
assertEquals(6, target.getStudents().get(1).id.getValue());
assertEquals(1, target.getId().getValue());
}
@SuppressWarnings("unused")
private static class Student {
Id<Student> id;
String name;
private Student() {
this(null, null);
}
public Student(Id<Student> id, String name) {
this.id = id;
this.name = name;
}
}
@SuppressWarnings("unused")
private static class Course<T> {
final List<Student> students;
private final Id<Course<T>> courseId;
private final int numAssignments;
private final Assignment<T> assignment;
private Course() {
this(null, 0, null, new ArrayList<Student>());
}
public Course(Id<Course<T>> courseId, int numAssignments,
Assignment<T> assignment, List<Student> players) {
this.courseId = courseId;
this.numAssignments = numAssignments;
this.assignment = assignment;
this.students = players;
}
public Id<Course<T>> getId() {
return courseId;
}
List<Student> getStudents() {
return students;
}
}
@SuppressWarnings("unused")
private static class Assignment<T> {
private final Id<Assignment<T>> id;
private final T data;
private Assignment() {
this(null, null);
}
public Assignment(Id<Assignment<T>> id, T data) {
this.id = id;
this.data = data;
}
}
@SuppressWarnings("unused")
private static class HistoryCourse {
int numClasses;
}
private static <T> List<T> createList(T ...items) {
return Arrays.asList(items);
}
}

View File

@ -15,24 +15,33 @@
*/
package com.google.gson.wsf.server.rest;
import java.util.HashMap;
import java.util.Map;
import com.google.gson.webservice.definition.rest.Id;
import com.google.gson.webservice.definition.rest.MetaData;
import com.google.gson.webservice.definition.rest.RestResource;
/**
* Metadata associated with a repository for a rest resource
* A map of resources to their MetaData
*
* @author inder
*
* @param <R> The resource
* @param <R> the rest resource for whic the metadata is being stored
*/
public final class MetaData<R extends RestResource<R>> {
public class MetaDataMap<R extends RestResource<R>> {
private final Map<Id<R>, MetaData<R>> map;
final boolean freshlyAssignedId;
public MetaData(boolean freshlyAssignedId) {
this.freshlyAssignedId = freshlyAssignedId;
public MetaDataMap() {
this.map = new HashMap<Id<R>, MetaData<R>>();
}
public boolean isFreshlyAssignedId() {
return freshlyAssignedId;
public MetaData<R> get(Id<R> resourceId) {
MetaData<R> metaData = map.get(resourceId);
if (metaData == null) {
metaData = MetaData.create();
map.put(resourceId, metaData);
}
return metaData;
}
}
}

View File

@ -18,6 +18,7 @@ package com.google.gson.wsf.server.rest;
import java.util.Map;
import com.google.gson.webservice.definition.rest.Id;
import com.google.gson.webservice.definition.rest.MetaData;
import com.google.gson.webservice.definition.rest.RestResource;
import com.google.inject.internal.Maps;
import com.google.inject.internal.Preconditions;
@ -30,12 +31,14 @@ import com.google.inject.internal.Preconditions;
* @param <R> Type variable for the resource
*/
public class RepositoryInMemory<R extends RestResource<R>> implements Repository<R> {
private static final String METADATA_KEY_IS_FRESHLY_ASSIGNED_ID = "isFreshlyAssignedId";
private final IdMap<R> resources;
private final Map<Id<R>, MetaData<R>> metaDataMap;
private final MetaDataMap<R> metaDataMap;
public RepositoryInMemory(Class<? super R> classOfResource) {
this.resources = IdMap.create(classOfResource);
this.metaDataMap = Maps.newHashMap();
this.metaDataMap = new MetaDataMap<R>();
}
@Override
@ -48,7 +51,7 @@ public class RepositoryInMemory<R extends RestResource<R>> implements Repository
if (metaData == null) {
return false;
}
return metaData.isFreshlyAssignedId();
return metaData.getBoolean(METADATA_KEY_IS_FRESHLY_ASSIGNED_ID);
}
@Override
@ -64,7 +67,7 @@ public class RepositoryInMemory<R extends RestResource<R>> implements Repository
}
}
resource = resources.put(resource);
metaDataMap.remove(resource.getId());
metaDataMap.get(resource.getId()).remove(METADATA_KEY_IS_FRESHLY_ASSIGNED_ID);
return resource;
}
@ -88,7 +91,7 @@ public class RepositoryInMemory<R extends RestResource<R>> implements Repository
if (resource.getId() == null) {
Id<R> id = resources.getNextId();
resource.setId(id);
metaDataMap.put(id, new MetaData<R>(true));
metaDataMap.get(id).putBoolean(METADATA_KEY_IS_FRESHLY_ASSIGNED_ID, true);
}
return resource.getId();
}