From 89ec269cc8c6895c8b88ffef1a203526c45d52c2 Mon Sep 17 00:00:00 2001 From: Sadegh Kazemy Date: Thu, 15 Sep 2016 15:59:29 +0430 Subject: [PATCH 1/2] Provide a generic json mapper for any entity. --- ...yJsonMapper.java => EntityJsonMapper.java} | 60 ++++++++++++------- .../sample/data/net/RestApiImpl.java | 16 ++--- .../datasource/UserDataStoreFactory.java | 7 ++- ...perTest.java => EntityMapperUtilTest.java} | 14 ++--- 4 files changed, 56 insertions(+), 41 deletions(-) rename data/src/main/java/com/fernandocejas/android10/sample/data/entity/mapper/{UserEntityJsonMapper.java => EntityJsonMapper.java} (54%) rename data/src/test/java/com/fernandocejas/android10/sample/data/entity/mapper/{UserEntityJsonMapperTest.java => EntityMapperUtilTest.java} (87%) diff --git a/data/src/main/java/com/fernandocejas/android10/sample/data/entity/mapper/UserEntityJsonMapper.java b/data/src/main/java/com/fernandocejas/android10/sample/data/entity/mapper/EntityJsonMapper.java similarity index 54% rename from data/src/main/java/com/fernandocejas/android10/sample/data/entity/mapper/UserEntityJsonMapper.java rename to data/src/main/java/com/fernandocejas/android10/sample/data/entity/mapper/EntityJsonMapper.java index 8e8dca90..17e41ed3 100644 --- a/data/src/main/java/com/fernandocejas/android10/sample/data/entity/mapper/UserEntityJsonMapper.java +++ b/data/src/main/java/com/fernandocejas/android10/sample/data/entity/mapper/EntityJsonMapper.java @@ -15,62 +15,76 @@ */ package com.fernandocejas.android10.sample.data.entity.mapper; -import com.fernandocejas.android10.sample.data.entity.UserEntity; import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; import com.google.gson.reflect.TypeToken; + +import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; -import javax.inject.Inject; /** * Class used to transform from Strings representing json to valid objects. */ -public class UserEntityJsonMapper { +public class EntityJsonMapper { private final Gson gson; + private final Type type; + private ParameterizedType parameterizedType; - @Inject - public UserEntityJsonMapper() { + public EntityJsonMapper(Class clazz) { this.gson = new Gson(); + this.type = clazz; } /** - * Transform from valid json string to {@link UserEntity}. + * Transform from valid json string to an object type {@link T}. * - * @param userJsonResponse A json representing a user profile. - * @return {@link UserEntity}. + * @param json A json representing an object type {@link T}. + * @return {@link T}. * @throws com.google.gson.JsonSyntaxException if the json string is not a valid json structure. */ - public UserEntity transformUserEntity(String userJsonResponse) throws JsonSyntaxException { + public T transformUserEntity(String json) throws JsonSyntaxException { try { - Type userEntityType = new TypeToken() {}.getType(); - UserEntity userEntity = this.gson.fromJson(userJsonResponse, userEntityType); - - return userEntity; + return gson.fromJson(json, type); } catch (JsonSyntaxException jsonException) { throw jsonException; } } /** - * Transform from valid json string to List of {@link UserEntity}. + * Transform from valid json string to List of {@link T}. * - * @param userListJsonResponse A json representing a collection of users. - * @return List of {@link UserEntity}. + * @param json A json representing a collection of objects type {@link T}. + * @return List of {@link T}. * @throws com.google.gson.JsonSyntaxException if the json string is not a valid json structure. */ - public List transformUserEntityCollection(String userListJsonResponse) + public List transformUserEntityCollection(String json) throws JsonSyntaxException { - - List userEntityCollection; try { - Type listOfUserEntityType = new TypeToken>() {}.getType(); - userEntityCollection = this.gson.fromJson(userListJsonResponse, listOfUserEntityType); - - return userEntityCollection; + return gson.fromJson(json, getParameterizedType()); } catch (JsonSyntaxException jsonException) { throw jsonException; } } + + private ParameterizedType getParameterizedType() { + if (parameterizedType == null) { + parameterizedType = new ParameterizedType() { + @Override public Type[] getActualTypeArguments() { + return new Type[] {type}; + } + + @Override public Type getOwnerType() { + return null; + } + + @Override public Type getRawType() { + return List.class; + } + }; + } + + return parameterizedType; + } } diff --git a/data/src/main/java/com/fernandocejas/android10/sample/data/net/RestApiImpl.java b/data/src/main/java/com/fernandocejas/android10/sample/data/net/RestApiImpl.java index 1450000f..426e39c8 100644 --- a/data/src/main/java/com/fernandocejas/android10/sample/data/net/RestApiImpl.java +++ b/data/src/main/java/com/fernandocejas/android10/sample/data/net/RestApiImpl.java @@ -19,7 +19,7 @@ import android.net.ConnectivityManager; import android.net.NetworkInfo; import com.fernandocejas.android10.sample.data.entity.UserEntity; -import com.fernandocejas.android10.sample.data.entity.mapper.UserEntityJsonMapper; +import com.fernandocejas.android10.sample.data.entity.mapper.EntityJsonMapper; import com.fernandocejas.android10.sample.data.exception.NetworkConnectionException; import com.fernandocejas.frodo.annotation.RxLogObservable; import java.net.MalformedURLException; @@ -32,20 +32,20 @@ public class RestApiImpl implements RestApi { private final Context context; - private final UserEntityJsonMapper userEntityJsonMapper; + private final EntityJsonMapper entityJsonMapper; /** * Constructor of the class * * @param context {@link android.content.Context}. - * @param userEntityJsonMapper {@link UserEntityJsonMapper}. + * @param entityJsonMapper {@link EntityJsonMapper}. */ - public RestApiImpl(Context context, UserEntityJsonMapper userEntityJsonMapper) { - if (context == null || userEntityJsonMapper == null) { + public RestApiImpl(Context context, EntityJsonMapper entityJsonMapper) { + if (context == null || entityJsonMapper == null) { throw new IllegalArgumentException("The constructor parameters cannot be null!!!"); } this.context = context.getApplicationContext(); - this.userEntityJsonMapper = userEntityJsonMapper; + this.entityJsonMapper = entityJsonMapper; } @RxLogObservable @@ -55,7 +55,7 @@ public RestApiImpl(Context context, UserEntityJsonMapper userEntityJsonMapper) { try { String responseUserEntities = getUserEntitiesFromApi(); if (responseUserEntities != null) { - subscriber.onNext(userEntityJsonMapper.transformUserEntityCollection( + subscriber.onNext(entityJsonMapper.transformUserEntityCollection( responseUserEntities)); subscriber.onCompleted(); } else { @@ -77,7 +77,7 @@ public RestApiImpl(Context context, UserEntityJsonMapper userEntityJsonMapper) { try { String responseUserDetails = getUserDetailsFromApi(userId); if (responseUserDetails != null) { - subscriber.onNext(userEntityJsonMapper.transformUserEntity(responseUserDetails)); + subscriber.onNext(entityJsonMapper.transformUserEntity(responseUserDetails)); subscriber.onCompleted(); } else { subscriber.onError(new NetworkConnectionException()); diff --git a/data/src/main/java/com/fernandocejas/android10/sample/data/repository/datasource/UserDataStoreFactory.java b/data/src/main/java/com/fernandocejas/android10/sample/data/repository/datasource/UserDataStoreFactory.java index 90c979e2..0b9599ec 100644 --- a/data/src/main/java/com/fernandocejas/android10/sample/data/repository/datasource/UserDataStoreFactory.java +++ b/data/src/main/java/com/fernandocejas/android10/sample/data/repository/datasource/UserDataStoreFactory.java @@ -18,7 +18,8 @@ import android.content.Context; import android.support.annotation.NonNull; import com.fernandocejas.android10.sample.data.cache.UserCache; -import com.fernandocejas.android10.sample.data.entity.mapper.UserEntityJsonMapper; +import com.fernandocejas.android10.sample.data.entity.UserEntity; +import com.fernandocejas.android10.sample.data.entity.mapper.EntityJsonMapper; import com.fernandocejas.android10.sample.data.net.RestApi; import com.fernandocejas.android10.sample.data.net.RestApiImpl; import javax.inject.Inject; @@ -58,8 +59,8 @@ public UserDataStore create(int userId) { * Create {@link UserDataStore} to retrieve data from the Cloud. */ public UserDataStore createCloudDataStore() { - UserEntityJsonMapper userEntityJsonMapper = new UserEntityJsonMapper(); - RestApi restApi = new RestApiImpl(this.context, userEntityJsonMapper); + EntityJsonMapper entityJsonMapper = new EntityJsonMapper<>(UserEntity.class); + RestApi restApi = new RestApiImpl(this.context, entityJsonMapper); return new CloudUserDataStore(restApi, this.userCache); } diff --git a/data/src/test/java/com/fernandocejas/android10/sample/data/entity/mapper/UserEntityJsonMapperTest.java b/data/src/test/java/com/fernandocejas/android10/sample/data/entity/mapper/EntityMapperUtilTest.java similarity index 87% rename from data/src/test/java/com/fernandocejas/android10/sample/data/entity/mapper/UserEntityJsonMapperTest.java rename to data/src/test/java/com/fernandocejas/android10/sample/data/entity/mapper/EntityMapperUtilTest.java index f834f52d..8707a12f 100644 --- a/data/src/test/java/com/fernandocejas/android10/sample/data/entity/mapper/UserEntityJsonMapperTest.java +++ b/data/src/test/java/com/fernandocejas/android10/sample/data/entity/mapper/EntityMapperUtilTest.java @@ -28,7 +28,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; -public class UserEntityJsonMapperTest extends ApplicationTestCase { +public class EntityMapperUtilTest extends ApplicationTestCase { private static final String JSON_RESPONSE_USER_DETAILS = "{\n" + " \"id\": 1,\n" @@ -49,19 +49,19 @@ public class UserEntityJsonMapperTest extends ApplicationTestCase { + " \"followers\": 1381\n" + "}]"; - private UserEntityJsonMapper userEntityJsonMapper; + private EntityJsonMapper entityJsonMapper; @Rule public ExpectedException expectedException = ExpectedException.none(); @Before public void setUp() { - userEntityJsonMapper = new UserEntityJsonMapper(); + entityJsonMapper = new EntityJsonMapper(UserEntity.class); } @Test public void testTransformUserEntityHappyCase() { - UserEntity userEntity = userEntityJsonMapper.transformUserEntity(JSON_RESPONSE_USER_DETAILS); + UserEntity userEntity = entityJsonMapper.transformUserEntity(JSON_RESPONSE_USER_DETAILS); assertThat(userEntity.getUserId(), is(1)); assertThat(userEntity.getFullname(), is(equalTo("Simon Hill"))); @@ -71,7 +71,7 @@ public void testTransformUserEntityHappyCase() { @Test public void testTransformUserEntityCollectionHappyCase() { Collection userEntityCollection = - userEntityJsonMapper.transformUserEntityCollection( + entityJsonMapper.transformUserEntityCollection( JSON_RESPONSE_USER_COLLECTION); assertThat(((UserEntity) userEntityCollection.toArray()[0]).getUserId(), is(1)); @@ -82,12 +82,12 @@ public void testTransformUserEntityCollectionHappyCase() { @Test public void testTransformUserEntityNotValidResponse() { expectedException.expect(JsonSyntaxException.class); - userEntityJsonMapper.transformUserEntity("ironman"); + entityJsonMapper.transformUserEntity("ironman"); } @Test public void testTransformUserEntityCollectionNotValidResponse() { expectedException.expect(JsonSyntaxException.class); - userEntityJsonMapper.transformUserEntityCollection("Tony Stark"); + entityJsonMapper.transformUserEntityCollection("Tony Stark"); } } From d4750185e9ab200acae086f2d259c59ebf0c8dc8 Mon Sep 17 00:00:00 2001 From: Sadegh Kazemy Date: Sat, 17 Sep 2016 18:59:57 +0430 Subject: [PATCH 2/2] Rename EntityJsonMapper methods to be generic. --- .../sample/data/entity/mapper/EntityJsonMapper.java | 4 ++-- .../android10/sample/data/net/RestApiImpl.java | 4 ++-- .../sample/data/entity/mapper/EntityMapperUtilTest.java | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/data/src/main/java/com/fernandocejas/android10/sample/data/entity/mapper/EntityJsonMapper.java b/data/src/main/java/com/fernandocejas/android10/sample/data/entity/mapper/EntityJsonMapper.java index 17e41ed3..17a578d4 100644 --- a/data/src/main/java/com/fernandocejas/android10/sample/data/entity/mapper/EntityJsonMapper.java +++ b/data/src/main/java/com/fernandocejas/android10/sample/data/entity/mapper/EntityJsonMapper.java @@ -44,7 +44,7 @@ public EntityJsonMapper(Class clazz) { * @return {@link T}. * @throws com.google.gson.JsonSyntaxException if the json string is not a valid json structure. */ - public T transformUserEntity(String json) throws JsonSyntaxException { + public T transformEntity(String json) throws JsonSyntaxException { try { return gson.fromJson(json, type); } catch (JsonSyntaxException jsonException) { @@ -59,7 +59,7 @@ public T transformUserEntity(String json) throws JsonSyntaxException { * @return List of {@link T}. * @throws com.google.gson.JsonSyntaxException if the json string is not a valid json structure. */ - public List transformUserEntityCollection(String json) + public List transformEntityCollection(String json) throws JsonSyntaxException { try { return gson.fromJson(json, getParameterizedType()); diff --git a/data/src/main/java/com/fernandocejas/android10/sample/data/net/RestApiImpl.java b/data/src/main/java/com/fernandocejas/android10/sample/data/net/RestApiImpl.java index 426e39c8..9f84d31d 100644 --- a/data/src/main/java/com/fernandocejas/android10/sample/data/net/RestApiImpl.java +++ b/data/src/main/java/com/fernandocejas/android10/sample/data/net/RestApiImpl.java @@ -55,7 +55,7 @@ public RestApiImpl(Context context, EntityJsonMapper entityJsonMapper) { try { String responseUserEntities = getUserEntitiesFromApi(); if (responseUserEntities != null) { - subscriber.onNext(entityJsonMapper.transformUserEntityCollection( + subscriber.onNext(entityJsonMapper.transformEntityCollection( responseUserEntities)); subscriber.onCompleted(); } else { @@ -77,7 +77,7 @@ public RestApiImpl(Context context, EntityJsonMapper entityJsonMapper) { try { String responseUserDetails = getUserDetailsFromApi(userId); if (responseUserDetails != null) { - subscriber.onNext(entityJsonMapper.transformUserEntity(responseUserDetails)); + subscriber.onNext(entityJsonMapper.transformEntity(responseUserDetails)); subscriber.onCompleted(); } else { subscriber.onError(new NetworkConnectionException()); diff --git a/data/src/test/java/com/fernandocejas/android10/sample/data/entity/mapper/EntityMapperUtilTest.java b/data/src/test/java/com/fernandocejas/android10/sample/data/entity/mapper/EntityMapperUtilTest.java index 8707a12f..746bb82b 100644 --- a/data/src/test/java/com/fernandocejas/android10/sample/data/entity/mapper/EntityMapperUtilTest.java +++ b/data/src/test/java/com/fernandocejas/android10/sample/data/entity/mapper/EntityMapperUtilTest.java @@ -61,7 +61,7 @@ public void setUp() { @Test public void testTransformUserEntityHappyCase() { - UserEntity userEntity = entityJsonMapper.transformUserEntity(JSON_RESPONSE_USER_DETAILS); + UserEntity userEntity = entityJsonMapper.transformEntity(JSON_RESPONSE_USER_DETAILS); assertThat(userEntity.getUserId(), is(1)); assertThat(userEntity.getFullname(), is(equalTo("Simon Hill"))); @@ -71,7 +71,7 @@ public void testTransformUserEntityHappyCase() { @Test public void testTransformUserEntityCollectionHappyCase() { Collection userEntityCollection = - entityJsonMapper.transformUserEntityCollection( + entityJsonMapper.transformEntityCollection( JSON_RESPONSE_USER_COLLECTION); assertThat(((UserEntity) userEntityCollection.toArray()[0]).getUserId(), is(1)); @@ -82,12 +82,12 @@ public void testTransformUserEntityCollectionHappyCase() { @Test public void testTransformUserEntityNotValidResponse() { expectedException.expect(JsonSyntaxException.class); - entityJsonMapper.transformUserEntity("ironman"); + entityJsonMapper.transformEntity("ironman"); } @Test public void testTransformUserEntityCollectionNotValidResponse() { expectedException.expect(JsonSyntaxException.class); - entityJsonMapper.transformUserEntityCollection("Tony Stark"); + entityJsonMapper.transformEntityCollection("Tony Stark"); } }