diff --git a/.travis.yml b/.travis.yml
index 0f3726f4..3cae64da 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,8 +3,18 @@ jdk: oraclejdk8
android:
components:
- - build-tools-23.0.1
- - android-21
+ - tools
+ - platform-tools
+ - tools
+ - build-tools-27.0.1
+ - android-26
+ - extra-google-m2repository
+ - extra-android-m2repository
+
+licenses:
+ - 'android-sdk-preview-license-.+'
+ - 'android-sdk-license-.+'
+ - 'google-gdk-license-.+'
script:
./gradlew build
diff --git a/README.md b/README.md
index 112b2e29..a060ce7e 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,11 @@
-Android-CleanArchitecture [](https://travis-ci.org/android10/Android-CleanArchitecture)
+Android-CleanArchitecture
=========================
+## New version available written in Kotlin:
+[Architecting Android… Reloaded](https://fernandocejas.com/2018/05/07/architecting-android-reloaded/)
+
+Introduction
+-----------------
This is a sample app that is part of a blog post I have written about how to architect android application using the Uncle Bob's clean architecture approach.
[Architecting Android…The clean way?](http://fernandocejas.com/2014/09/03/architecting-android-the-clean-way/)
@@ -9,19 +14,21 @@ This is a sample app that is part of a blog post I have written about how to arc
[Tasting Dagger 2 on Android](http://fernandocejas.com/2015/04/11/tasting-dagger-2-on-android/)
+[Clean Architecture…Dynamic Parameters in Use Cases](http://fernandocejas.com/2016/12/24/clean-architecture-dynamic-parameters-in-use-cases/)
+
[Demo video of this sample](http://youtu.be/XSjV4sG3ni0)
Clean architecture
-----------------
-
+
Architectural approach
-----------------
-
+
Architectural reactive approach
-----------------
-
+
Local Development
-----------------
@@ -49,7 +56,7 @@ https://github.com/android10/java-code-styles
License
--------
- Copyright 2014 Fernando Cejas
+ Copyright 2018 Fernando Cejas
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -64,6 +71,8 @@ License
limitations under the License.
-
+
[](https://android-arsenal.com/details/3/909)
+
+
diff --git a/build.gradle b/build.gradle
index 54470a60..d951c72d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,11 +5,11 @@ buildscript {
repositories {
jcenter()
mavenCentral()
+ google()
}
dependencies {
- classpath 'com.android.tools.build:gradle:1.5.0'
- classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
- classpath "com.fernandocejas.frodo:frodo-plugin:0.8.1"
+ classpath 'com.android.tools.build:gradle:3.0.1'
+// classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
}
}
@@ -23,11 +23,6 @@ allprojects {
}
}
-task wrapper(type: Wrapper) {
- description 'Creates the gradle wrapper.'
- gradleVersion '2.10'
-}
-
task runDomainUnitTests(dependsOn: [':domain:test']) {
description 'Run unit tests for the domain layer.'
}
diff --git a/buildsystem/dependencies.gradle b/buildsystem/dependencies.gradle
index aedb3ab5..ba467503 100644
--- a/buildsystem/dependencies.gradle
+++ b/buildsystem/dependencies.gradle
@@ -6,29 +6,31 @@ allprojects {
ext {
//Android
- androidBuildToolsVersion = "23.0.1"
+ androidBuildToolsVersion = "27.0.1"
androidMinSdkVersion = 15
- androidTargetSdkVersion = 21
- androidCompileSdkVersion = 21
+ androidTargetSdkVersion = 26
+ androidCompileSdkVersion = 26
//Libraries
- daggerVersion = '2.0.2'
+ daggerVersion = '2.8'
butterKnifeVersion = '7.0.1'
- recyclerViewVersion = '21.0.3'
- rxJavaVersion = '1.0.14'
- rxAndroidVersion = '1.0.1'
+ recyclerViewVersion = '25.4.0'
+ rxJavaVersion = '2.0.2'
+ rxAndroidVersion = '2.0.1'
javaxAnnotationVersion = '1.0'
+ javaxInjectVersion = '1'
gsonVersion = '2.3'
okHttpVersion = '2.5.0'
- androidAnnotationsVersion = '21.0.3'
+ androidAnnotationsVersion = '25.4.0'
+ arrowVersion = '1.0.0'
//Testing
- robolectricVersion = '3.0'
+ robolectricVersion = '3.1.1'
jUnitVersion = '4.12'
assertJVersion = '1.7.1'
mockitoVersion = '1.9.5'
dexmakerVersion = '1.0'
- espressoVersion = '2.0'
+ espressoVersion = '3.0.1'
testingSupportLibVersion = '0.1'
//Development
@@ -39,9 +41,9 @@ ext {
dagger: "com.google.dagger:dagger:${daggerVersion}",
butterKnife: "com.jakewharton:butterknife:${butterKnifeVersion}",
recyclerView: "com.android.support:recyclerview-v7:${recyclerViewVersion}",
- rxJava: "io.reactivex:rxjava:${rxJavaVersion}",
- rxAndroid: "io.reactivex:rxandroid:${rxAndroidVersion}",
- javaxAnnotation: "javax.annotation:jsr250-api:${javaxAnnotationVersion}",
+ rxJava: "io.reactivex.rxjava2:rxjava:${rxJavaVersion}",
+ rxAndroid: "io.reactivex.rxjava2:rxandroid:${rxAndroidVersion}",
+ javaxAnnotation: "javax.annotation:jsr250-api:${javaxAnnotationVersion}"
]
presentationTestDependencies = [
@@ -53,15 +55,16 @@ ext {
]
domainDependencies = [
- daggerCompiler: "com.google.dagger:dagger-compiler:${daggerVersion}",
- dagger: "com.google.dagger:dagger:${daggerVersion}",
javaxAnnotation: "javax.annotation:jsr250-api:${javaxAnnotationVersion}",
- rxJava: "io.reactivex:rxjava:${rxJavaVersion}",
+ javaxInject: "javax.inject:javax.inject:${javaxInjectVersion}",
+ rxJava: "io.reactivex.rxjava2:rxjava:${rxJavaVersion}",
+ arrow: "com.fernandocejas:arrow:${arrowVersion}"
]
domainTestDependencies = [
junit: "junit:junit:${jUnitVersion}",
mockito: "org.mockito:mockito-core:${mockitoVersion}",
+ assertj: "org.assertj:assertj-core:${assertJVersion}"
]
dataDependencies = [
@@ -69,9 +72,10 @@ ext {
dagger: "com.google.dagger:dagger:${daggerVersion}",
okHttp: "com.squareup.okhttp:okhttp:${okHttpVersion}",
gson: "com.google.code.gson:gson:${gsonVersion}",
- rxJava: "io.reactivex:rxjava:${rxJavaVersion}",
- rxAndroid: "io.reactivex:rxandroid:${rxAndroidVersion}",
+ rxJava: "io.reactivex.rxjava2:rxjava:${rxJavaVersion}",
+ rxAndroid: "io.reactivex.rxjava2:rxandroid:${rxAndroidVersion}",
javaxAnnotation: "javax.annotation:jsr250-api:${javaxAnnotationVersion}",
+ javaxInject: "javax.inject:javax.inject:${javaxInjectVersion}",
androidAnnotations: "com.android.support:support-annotations:${androidAnnotationsVersion}"
]
diff --git a/data/build.gradle b/data/build.gradle
index 8d358887..e1f55a6a 100644
--- a/data/build.gradle
+++ b/data/build.gradle
@@ -3,13 +3,12 @@ buildscript {
mavenCentral()
}
dependencies {
- classpath 'me.tatarka:gradle-retrolambda:3.2.3'
+ classpath 'me.tatarka:gradle-retrolambda:3.7.0'
}
}
apply plugin: 'com.android.library'
-apply plugin: 'com.neenbedankt.android-apt'
-apply plugin: 'com.fernandocejas.frodo'
+//apply plugin: 'com.neenbedankt.android-apt'
apply plugin: 'me.tatarka.retrolambda'
android {
@@ -52,18 +51,21 @@ dependencies {
def dataDependencies = rootProject.ext.dataDependencies
def testDependencies = rootProject.ext.dataTestDependencies
- compile project(':domain')
- apt dataDependencies.daggerCompiler
- provided dataDependencies.javaxAnnotation
- compile dataDependencies.dagger
- compile dataDependencies.okHttp
- compile dataDependencies.gson
- compile dataDependencies.rxJava
- compile dataDependencies.rxAndroid
- compile dataDependencies.androidAnnotations
+ implementation project(':domain')
+ compileOnly dataDependencies.javaxAnnotation
+ implementation dataDependencies.javaxInject
+ implementation dataDependencies.okHttp
+ implementation dataDependencies.gson
+ implementation dataDependencies.rxJava
+ implementation dataDependencies.rxAndroid
+ implementation dataDependencies.androidAnnotations
- testCompile testDependencies.junit
- testCompile testDependencies.assertj
- testCompile testDependencies.mockito
- testCompile testDependencies.robolectric
+ testImplementation testDependencies.junit
+ testImplementation testDependencies.assertj
+ testImplementation testDependencies.mockito
+ testImplementation testDependencies.robolectric
}
+
+repositories {
+ google()
+}
\ No newline at end of file
diff --git a/data/src/main/java/com/fernandocejas/android10/sample/data/cache/FileManager.java b/data/src/main/java/com/fernandocejas/android10/sample/data/cache/FileManager.java
index 670ee93f..62d99d76 100644
--- a/data/src/main/java/com/fernandocejas/android10/sample/data/cache/FileManager.java
+++ b/data/src/main/java/com/fernandocejas/android10/sample/data/cache/FileManager.java
@@ -19,7 +19,6 @@
import android.content.SharedPreferences;
import java.io.BufferedReader;
import java.io.File;
-import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
@@ -33,7 +32,7 @@
public class FileManager {
@Inject
- public FileManager() {}
+ FileManager() {}
/**
* Writes a file to Disk.
@@ -42,18 +41,14 @@ public FileManager() {}
*
* @param file The file to write to Disk.
*/
- public void writeToFile(File file, String fileContent) {
+ void writeToFile(File file, String fileContent) {
if (!file.exists()) {
try {
- FileWriter writer = new FileWriter(file);
+ final FileWriter writer = new FileWriter(file);
writer.write(fileContent);
writer.close();
- } catch (FileNotFoundException e) {
- e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
- } finally {
-
}
}
}
@@ -66,25 +61,22 @@ public void writeToFile(File file, String fileContent) {
* @param file The file to read from.
* @return A string with the content of the file.
*/
- public String readFileContent(File file) {
- StringBuilder fileContentBuilder = new StringBuilder();
+ String readFileContent(File file) {
+ final StringBuilder fileContentBuilder = new StringBuilder();
if (file.exists()) {
String stringLine;
try {
- FileReader fileReader = new FileReader(file);
- BufferedReader bufferedReader = new BufferedReader(fileReader);
+ final FileReader fileReader = new FileReader(file);
+ final BufferedReader bufferedReader = new BufferedReader(fileReader);
while ((stringLine = bufferedReader.readLine()) != null) {
- fileContentBuilder.append(stringLine + "\n");
+ fileContentBuilder.append(stringLine).append("\n");
}
bufferedReader.close();
fileReader.close();
- } catch (FileNotFoundException e) {
- e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
-
return fileContentBuilder.toString();
}
@@ -94,7 +86,7 @@ public String readFileContent(File file) {
* @param file The file to check existence.
* @return true if this file exists, false otherwise.
*/
- public boolean exists(File file) {
+ boolean exists(File file) {
return file.exists();
}
@@ -105,12 +97,14 @@ public boolean exists(File file) {
*
* @param directory The directory which its content will be deleted.
*/
- public void clearDirectory(File directory) {
+ boolean clearDirectory(File directory) {
+ boolean result = false;
if (directory.exists()) {
for (File file : directory.listFiles()) {
- file.delete();
+ result = file.delete();
}
}
+ return result;
}
/**
@@ -121,12 +115,12 @@ public void clearDirectory(File directory) {
* @param key A string for the key that will be used to retrieve the value in the future.
* @param value A long representing the value to be inserted.
*/
- public void writeToPreferences(Context context, String preferenceFileName, String key,
+ void writeToPreferences(Context context, String preferenceFileName, String key,
long value) {
- SharedPreferences sharedPreferences = context.getSharedPreferences(preferenceFileName,
+ final SharedPreferences sharedPreferences = context.getSharedPreferences(preferenceFileName,
Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = sharedPreferences.edit();
+ final SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putLong(key, value);
editor.apply();
}
@@ -139,8 +133,8 @@ public void writeToPreferences(Context context, String preferenceFileName, Strin
* @param key A key that will be used to retrieve the value from the preference file.
* @return A long representing the value retrieved from the preferences file.
*/
- public long getFromPreferences(Context context, String preferenceFileName, String key) {
- SharedPreferences sharedPreferences = context.getSharedPreferences(preferenceFileName,
+ long getFromPreferences(Context context, String preferenceFileName, String key) {
+ final SharedPreferences sharedPreferences = context.getSharedPreferences(preferenceFileName,
Context.MODE_PRIVATE);
return sharedPreferences.getLong(key, 0);
}
diff --git a/data/src/main/java/com/fernandocejas/android10/sample/data/cache/UserCache.java b/data/src/main/java/com/fernandocejas/android10/sample/data/cache/UserCache.java
index 302cb760..1fe53a04 100644
--- a/data/src/main/java/com/fernandocejas/android10/sample/data/cache/UserCache.java
+++ b/data/src/main/java/com/fernandocejas/android10/sample/data/cache/UserCache.java
@@ -16,14 +16,14 @@
package com.fernandocejas.android10.sample.data.cache;
import com.fernandocejas.android10.sample.data.entity.UserEntity;
-import rx.Observable;
+import io.reactivex.Observable;
/**
* An interface representing a user Cache.
*/
public interface UserCache {
/**
- * Gets an {@link rx.Observable} which will emit a {@link UserEntity}.
+ * Gets an {@link Observable} which will emit a {@link UserEntity}.
*
* @param userId The user id to retrieve data.
*/
diff --git a/data/src/main/java/com/fernandocejas/android10/sample/data/cache/UserCacheImpl.java b/data/src/main/java/com/fernandocejas/android10/sample/data/cache/UserCacheImpl.java
index a7252f48..cc4351e0 100644
--- a/data/src/main/java/com/fernandocejas/android10/sample/data/cache/UserCacheImpl.java
+++ b/data/src/main/java/com/fernandocejas/android10/sample/data/cache/UserCacheImpl.java
@@ -5,7 +5,7 @@
* 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
+ * 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,
@@ -16,14 +16,14 @@
package com.fernandocejas.android10.sample.data.cache;
import android.content.Context;
-import com.fernandocejas.android10.sample.data.cache.serializer.JsonSerializer;
+import com.fernandocejas.android10.sample.data.cache.serializer.Serializer;
import com.fernandocejas.android10.sample.data.entity.UserEntity;
import com.fernandocejas.android10.sample.data.exception.UserNotFoundException;
import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
+import io.reactivex.Observable;
import java.io.File;
import javax.inject.Inject;
import javax.inject.Singleton;
-import rx.Observable;
/**
* {@link UserCache} implementation.
@@ -39,7 +39,7 @@ public class UserCacheImpl implements UserCache {
private final Context context;
private final File cacheDir;
- private final JsonSerializer serializer;
+ private final Serializer serializer;
private final FileManager fileManager;
private final ThreadExecutor threadExecutor;
@@ -47,52 +47,51 @@ public class UserCacheImpl implements UserCache {
* Constructor of the class {@link UserCacheImpl}.
*
* @param context A
- * @param userCacheSerializer {@link JsonSerializer} for object serialization.
+ * @param serializer {@link Serializer} for object serialization.
* @param fileManager {@link FileManager} for saving serialized objects to the file system.
*/
- @Inject
- public UserCacheImpl(Context context, JsonSerializer userCacheSerializer,
+ @Inject UserCacheImpl(Context context, Serializer serializer,
FileManager fileManager, ThreadExecutor executor) {
- if (context == null || userCacheSerializer == null || fileManager == null || executor == null) {
+ if (context == null || serializer == null || fileManager == null || executor == null) {
throw new IllegalArgumentException("Invalid null parameter");
}
this.context = context.getApplicationContext();
this.cacheDir = this.context.getCacheDir();
- this.serializer = userCacheSerializer;
+ this.serializer = serializer;
this.fileManager = fileManager;
this.threadExecutor = executor;
}
@Override public Observable get(final int userId) {
- return Observable.create(subscriber -> {
- File userEntityFile = UserCacheImpl.this.buildFile(userId);
- String fileContent = UserCacheImpl.this.fileManager.readFileContent(userEntityFile);
- UserEntity userEntity = UserCacheImpl.this.serializer.deserialize(fileContent);
+ return Observable.create(emitter -> {
+ final File userEntityFile = UserCacheImpl.this.buildFile(userId);
+ final String fileContent = UserCacheImpl.this.fileManager.readFileContent(userEntityFile);
+ final UserEntity userEntity =
+ UserCacheImpl.this.serializer.deserialize(fileContent, UserEntity.class);
if (userEntity != null) {
- subscriber.onNext(userEntity);
- subscriber.onCompleted();
+ emitter.onNext(userEntity);
+ emitter.onComplete();
} else {
- subscriber.onError(new UserNotFoundException());
+ emitter.onError(new UserNotFoundException());
}
});
}
@Override public void put(UserEntity userEntity) {
if (userEntity != null) {
- File userEntitiyFile = this.buildFile(userEntity.getUserId());
+ final File userEntityFile = this.buildFile(userEntity.getUserId());
if (!isCached(userEntity.getUserId())) {
- String jsonString = this.serializer.serialize(userEntity);
- this.executeAsynchronously(new CacheWriter(this.fileManager, userEntitiyFile,
- jsonString));
+ final String jsonString = this.serializer.serialize(userEntity, UserEntity.class);
+ this.executeAsynchronously(new CacheWriter(this.fileManager, userEntityFile, jsonString));
setLastCacheUpdateTimeMillis();
}
}
}
@Override public boolean isCached(int userId) {
- File userEntitiyFile = this.buildFile(userId);
- return this.fileManager.exists(userEntitiyFile);
+ final File userEntityFile = this.buildFile(userId);
+ return this.fileManager.exists(userEntityFile);
}
@Override public boolean isExpired() {
@@ -119,7 +118,7 @@ public UserCacheImpl(Context context, JsonSerializer userCacheSerializer,
* @return A valid file.
*/
private File buildFile(int userId) {
- StringBuilder fileNameBuilder = new StringBuilder();
+ final StringBuilder fileNameBuilder = new StringBuilder();
fileNameBuilder.append(this.cacheDir.getPath());
fileNameBuilder.append(File.separator);
fileNameBuilder.append(DEFAULT_FILE_NAME);
@@ -132,7 +131,7 @@ private File buildFile(int userId) {
* Set in millis, the last time the cache was accessed.
*/
private void setLastCacheUpdateTimeMillis() {
- long currentMillis = System.currentTimeMillis();
+ final long currentMillis = System.currentTimeMillis();
this.fileManager.writeToPreferences(this.context, SETTINGS_FILE_NAME,
SETTINGS_KEY_LAST_CACHE_UPDATE, currentMillis);
}
diff --git a/data/src/main/java/com/fernandocejas/android10/sample/data/cache/serializer/JsonSerializer.java b/data/src/main/java/com/fernandocejas/android10/sample/data/cache/serializer/Serializer.java
similarity index 60%
rename from data/src/main/java/com/fernandocejas/android10/sample/data/cache/serializer/JsonSerializer.java
rename to data/src/main/java/com/fernandocejas/android10/sample/data/cache/serializer/Serializer.java
index 6e053187..f9a9c100 100644
--- a/data/src/main/java/com/fernandocejas/android10/sample/data/cache/serializer/JsonSerializer.java
+++ b/data/src/main/java/com/fernandocejas/android10/sample/data/cache/serializer/Serializer.java
@@ -15,40 +15,35 @@
*/
package com.fernandocejas.android10.sample.data.cache.serializer;
-import com.fernandocejas.android10.sample.data.entity.UserEntity;
import com.google.gson.Gson;
import javax.inject.Inject;
import javax.inject.Singleton;
/**
- * Class user as Serializer/Deserializer for user entities.
+ * Json Serializer/Deserializer.
*/
@Singleton
-public class JsonSerializer {
+public class Serializer {
private final Gson gson = new Gson();
- @Inject
- public JsonSerializer() {}
+ @Inject Serializer() {}
/**
* Serialize an object to Json.
*
- * @param userEntity {@link UserEntity} to serialize.
+ * @param object to serialize.
*/
- public String serialize(UserEntity userEntity) {
- String jsonString = gson.toJson(userEntity, UserEntity.class);
- return jsonString;
+ public String serialize(Object object, Class clazz) {
+ return gson.toJson(object, clazz);
}
/**
* Deserialize a json representation of an object.
*
- * @param jsonString A json string to deserialize.
- * @return {@link UserEntity}
+ * @param string A json string to deserialize.
*/
- public UserEntity deserialize(String jsonString) {
- UserEntity userEntity = gson.fromJson(jsonString, UserEntity.class);
- return userEntity;
+ public T deserialize(String string, Class clazz) {
+ return gson.fromJson(string, clazz);
}
}
diff --git a/data/src/main/java/com/fernandocejas/android10/sample/data/entity/UserEntity.java b/data/src/main/java/com/fernandocejas/android10/sample/data/entity/UserEntity.java
index 8d8fb1fc..550e9acf 100644
--- a/data/src/main/java/com/fernandocejas/android10/sample/data/entity/UserEntity.java
+++ b/data/src/main/java/com/fernandocejas/android10/sample/data/entity/UserEntity.java
@@ -56,10 +56,6 @@ public String getCoverUrl() {
return coverUrl;
}
- public void setCoverUrl(String coverUrl) {
- this.coverUrl = coverUrl;
- }
-
public String getFullname() {
return fullname;
}
@@ -72,38 +68,11 @@ public String getDescription() {
return description;
}
- public void setDescription(String description) {
- this.description = description;
- }
-
public int getFollowers() {
return followers;
}
- public void setFollowers(int followers) {
- this.followers = followers;
- }
-
public String getEmail() {
return email;
}
-
- public void setEmail(String email) {
- this.email = email;
- }
-
- @Override public String toString() {
- StringBuilder stringBuilder = new StringBuilder();
-
- stringBuilder.append("***** User Entity Details *****\n");
- stringBuilder.append("id=" + this.getUserId() + "\n");
- stringBuilder.append("cover url=" + this.getCoverUrl() + "\n");
- stringBuilder.append("fullname=" + this.getFullname() + "\n");
- stringBuilder.append("email=" + this.getEmail() + "\n");
- stringBuilder.append("description=" + this.getDescription() + "\n");
- stringBuilder.append("followers=" + this.getFollowers() + "\n");
- stringBuilder.append("*******************************");
-
- return stringBuilder.toString();
- }
}
diff --git a/data/src/main/java/com/fernandocejas/android10/sample/data/entity/mapper/UserEntityDataMapper.java b/data/src/main/java/com/fernandocejas/android10/sample/data/entity/mapper/UserEntityDataMapper.java
index 1ecbdcdc..e2bde175 100644
--- a/data/src/main/java/com/fernandocejas/android10/sample/data/entity/mapper/UserEntityDataMapper.java
+++ b/data/src/main/java/com/fernandocejas/android10/sample/data/entity/mapper/UserEntityDataMapper.java
@@ -31,7 +31,7 @@
public class UserEntityDataMapper {
@Inject
- public UserEntityDataMapper() {}
+ UserEntityDataMapper() {}
/**
* Transform a {@link UserEntity} into an {@link User}.
@@ -49,7 +49,6 @@ public User transform(UserEntity userEntity) {
user.setFollowers(userEntity.getFollowers());
user.setEmail(userEntity.getEmail());
}
-
return user;
}
@@ -60,15 +59,13 @@ public User transform(UserEntity userEntity) {
* @return {@link User} if valid {@link UserEntity} otherwise null.
*/
public List transform(Collection userEntityCollection) {
- List userList = new ArrayList<>(20);
- User user;
+ final List userList = new ArrayList<>(20);
for (UserEntity userEntity : userEntityCollection) {
- user = transform(userEntity);
+ final User user = transform(userEntity);
if (user != null) {
userList.add(user);
}
}
-
return userList;
}
}
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/UserEntityJsonMapper.java
index 8e8dca90..1e344a34 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/UserEntityJsonMapper.java
@@ -43,14 +43,8 @@ public UserEntityJsonMapper() {
* @throws com.google.gson.JsonSyntaxException if the json string is not a valid json structure.
*/
public UserEntity transformUserEntity(String userJsonResponse) throws JsonSyntaxException {
- try {
- Type userEntityType = new TypeToken() {}.getType();
- UserEntity userEntity = this.gson.fromJson(userJsonResponse, userEntityType);
-
- return userEntity;
- } catch (JsonSyntaxException jsonException) {
- throw jsonException;
- }
+ final Type userEntityType = new TypeToken() {}.getType();
+ return this.gson.fromJson(userJsonResponse, userEntityType);
}
/**
@@ -62,15 +56,7 @@ public UserEntity transformUserEntity(String userJsonResponse) throws JsonSyntax
*/
public List transformUserEntityCollection(String userListJsonResponse)
throws JsonSyntaxException {
-
- List userEntityCollection;
- try {
- Type listOfUserEntityType = new TypeToken>() {}.getType();
- userEntityCollection = this.gson.fromJson(userListJsonResponse, listOfUserEntityType);
-
- return userEntityCollection;
- } catch (JsonSyntaxException jsonException) {
- throw jsonException;
- }
+ final Type listOfUserEntityType = new TypeToken>() {}.getType();
+ return this.gson.fromJson(userListJsonResponse, listOfUserEntityType);
}
}
diff --git a/data/src/main/java/com/fernandocejas/android10/sample/data/exception/NetworkConnectionException.java b/data/src/main/java/com/fernandocejas/android10/sample/data/exception/NetworkConnectionException.java
index 987a106b..a02ea8f4 100644
--- a/data/src/main/java/com/fernandocejas/android10/sample/data/exception/NetworkConnectionException.java
+++ b/data/src/main/java/com/fernandocejas/android10/sample/data/exception/NetworkConnectionException.java
@@ -24,14 +24,6 @@ public NetworkConnectionException() {
super();
}
- public NetworkConnectionException(final String message) {
- super(message);
- }
-
- public NetworkConnectionException(final String message, final Throwable cause) {
- super(message, cause);
- }
-
public NetworkConnectionException(final Throwable cause) {
super(cause);
}
diff --git a/data/src/main/java/com/fernandocejas/android10/sample/data/exception/RepositoryErrorBundle.java b/data/src/main/java/com/fernandocejas/android10/sample/data/exception/RepositoryErrorBundle.java
index c51144c4..a4ec28a2 100644
--- a/data/src/main/java/com/fernandocejas/android10/sample/data/exception/RepositoryErrorBundle.java
+++ b/data/src/main/java/com/fernandocejas/android10/sample/data/exception/RepositoryErrorBundle.java
@@ -5,7 +5,7 @@
* 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
+ * 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,
@@ -20,11 +20,11 @@
/**
* Wrapper around Exceptions used to manage errors in the repository.
*/
-public class RepositoryErrorBundle implements ErrorBundle {
+class RepositoryErrorBundle implements ErrorBundle {
private final Exception exception;
- public RepositoryErrorBundle(Exception exception) {
+ RepositoryErrorBundle(Exception exception) {
this.exception = exception;
}
@@ -37,7 +37,7 @@ public Exception getException() {
public String getErrorMessage() {
String message = "";
if (this.exception != null) {
- this.exception.getMessage();
+ message = this.exception.getMessage();
}
return message;
}
diff --git a/data/src/main/java/com/fernandocejas/android10/sample/data/exception/UserNotFoundException.java b/data/src/main/java/com/fernandocejas/android10/sample/data/exception/UserNotFoundException.java
index 8667eaa4..3865818d 100644
--- a/data/src/main/java/com/fernandocejas/android10/sample/data/exception/UserNotFoundException.java
+++ b/data/src/main/java/com/fernandocejas/android10/sample/data/exception/UserNotFoundException.java
@@ -5,7 +5,7 @@
* 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
+ * 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,
@@ -19,20 +19,7 @@
* Exception throw by the application when a User search can't return a valid result.
*/
public class UserNotFoundException extends Exception {
-
public UserNotFoundException() {
super();
}
-
- public UserNotFoundException(final String message) {
- super(message);
- }
-
- public UserNotFoundException(final String message, final Throwable cause) {
- super(message, cause);
- }
-
- public UserNotFoundException(final Throwable cause) {
- super(cause);
- }
}
diff --git a/data/src/main/java/com/fernandocejas/android10/sample/data/executor/JobExecutor.java b/data/src/main/java/com/fernandocejas/android10/sample/data/executor/JobExecutor.java
index c82177d0..f0963cec 100644
--- a/data/src/main/java/com/fernandocejas/android10/sample/data/executor/JobExecutor.java
+++ b/data/src/main/java/com/fernandocejas/android10/sample/data/executor/JobExecutor.java
@@ -15,8 +15,8 @@
*/
package com.fernandocejas.android10.sample.data.executor;
+import android.support.annotation.NonNull;
import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
-import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
@@ -29,43 +29,23 @@
*/
@Singleton
public class JobExecutor implements ThreadExecutor {
-
- private static final int INITIAL_POOL_SIZE = 3;
- private static final int MAX_POOL_SIZE = 5;
-
- // Sets the amount of time an idle thread waits before terminating
- private static final int KEEP_ALIVE_TIME = 10;
-
- // Sets the Time Unit to seconds
- private static final TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;
-
- private final BlockingQueue workQueue;
-
private final ThreadPoolExecutor threadPoolExecutor;
- private final ThreadFactory threadFactory;
-
@Inject
- public JobExecutor() {
- this.workQueue = new LinkedBlockingQueue<>();
- this.threadFactory = new JobThreadFactory();
- this.threadPoolExecutor = new ThreadPoolExecutor(INITIAL_POOL_SIZE, MAX_POOL_SIZE,
- KEEP_ALIVE_TIME, KEEP_ALIVE_TIME_UNIT, this.workQueue, this.threadFactory);
+ JobExecutor() {
+ this.threadPoolExecutor = new ThreadPoolExecutor(3, 5, 10, TimeUnit.SECONDS,
+ new LinkedBlockingQueue<>(), new JobThreadFactory());
}
- @Override public void execute(Runnable runnable) {
- if (runnable == null) {
- throw new IllegalArgumentException("Runnable to execute cannot be null");
- }
+ @Override public void execute(@NonNull Runnable runnable) {
this.threadPoolExecutor.execute(runnable);
}
private static class JobThreadFactory implements ThreadFactory {
- private static final String THREAD_NAME = "android_";
private int counter = 0;
- @Override public Thread newThread(Runnable runnable) {
- return new Thread(runnable, THREAD_NAME + counter++);
+ @Override public Thread newThread(@NonNull Runnable runnable) {
+ return new Thread(runnable, "android_" + counter++);
}
}
}
diff --git a/data/src/main/java/com/fernandocejas/android10/sample/data/net/ApiConnection.java b/data/src/main/java/com/fernandocejas/android10/sample/data/net/ApiConnection.java
index b5e153b7..7cf859d2 100644
--- a/data/src/main/java/com/fernandocejas/android10/sample/data/net/ApiConnection.java
+++ b/data/src/main/java/com/fernandocejas/android10/sample/data/net/ApiConnection.java
@@ -29,7 +29,7 @@
* Implements {@link java.util.concurrent.Callable} so when executed asynchronously can
* return a value.
*/
-public class ApiConnection implements Callable {
+class ApiConnection implements Callable {
private static final String CONTENT_TYPE_LABEL = "Content-Type";
private static final String CONTENT_TYPE_VALUE_JSON = "application/json; charset=utf-8";
@@ -41,7 +41,7 @@ private ApiConnection(String url) throws MalformedURLException {
this.url = new URL(url);
}
- public static ApiConnection createGET(String url) throws MalformedURLException {
+ static ApiConnection createGET(String url) throws MalformedURLException {
return new ApiConnection(url);
}
@@ -52,7 +52,7 @@ public static ApiConnection createGET(String url) throws MalformedURLException {
* @return A string response
*/
@Nullable
- public String requestSyncCall() {
+ String requestSyncCall() {
connectToApi();
return response;
}
diff --git a/data/src/main/java/com/fernandocejas/android10/sample/data/net/RestApi.java b/data/src/main/java/com/fernandocejas/android10/sample/data/net/RestApi.java
index f99d8f52..004acd6a 100644
--- a/data/src/main/java/com/fernandocejas/android10/sample/data/net/RestApi.java
+++ b/data/src/main/java/com/fernandocejas/android10/sample/data/net/RestApi.java
@@ -5,7 +5,7 @@
* 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
+ * 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,
@@ -16,14 +16,15 @@
package com.fernandocejas.android10.sample.data.net;
import com.fernandocejas.android10.sample.data.entity.UserEntity;
+import io.reactivex.Observable;
import java.util.List;
-import rx.Observable;
/**
* RestApi for retrieving data from the network.
*/
public interface RestApi {
- String API_BASE_URL = "http://www.android10.org/myapi/";
+ String API_BASE_URL =
+ "https://raw.githubusercontent.com/android10/Sample-Data/master/Android-CleanArchitecture/";
/** Api url for getting all users */
String API_URL_GET_USER_LIST = API_BASE_URL + "users.json";
@@ -31,12 +32,12 @@ public interface RestApi {
String API_URL_GET_USER_DETAILS = API_BASE_URL + "user_";
/**
- * Retrieves an {@link rx.Observable} which will emit a List of {@link UserEntity}.
+ * Retrieves an {@link Observable} which will emit a List of {@link UserEntity}.
*/
Observable> userEntityList();
/**
- * Retrieves an {@link rx.Observable} which will emit a {@link UserEntity}.
+ * Retrieves an {@link Observable} which will emit a {@link UserEntity}.
*
* @param userId The user id used to get user data.
*/
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 6b15518b..279fe6f4 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
@@ -21,10 +21,9 @@
import com.fernandocejas.android10.sample.data.entity.UserEntity;
import com.fernandocejas.android10.sample.data.entity.mapper.UserEntityJsonMapper;
import com.fernandocejas.android10.sample.data.exception.NetworkConnectionException;
-import com.fernandocejas.frodo.annotation.RxLogObservable;
+import io.reactivex.Observable;
import java.net.MalformedURLException;
import java.util.List;
-import rx.Observable;
/**
* {@link RestApi} implementation for retrieving data from the network.
@@ -48,55 +47,53 @@ public RestApiImpl(Context context, UserEntityJsonMapper userEntityJsonMapper) {
this.userEntityJsonMapper = userEntityJsonMapper;
}
- @RxLogObservable
@Override public Observable> userEntityList() {
- return Observable.create(subscriber -> {
+ return Observable.create(emitter -> {
if (isThereInternetConnection()) {
try {
String responseUserEntities = getUserEntitiesFromApi();
if (responseUserEntities != null) {
- subscriber.onNext(userEntityJsonMapper.transformUserEntityCollection(
+ emitter.onNext(userEntityJsonMapper.transformUserEntityCollection(
responseUserEntities));
- subscriber.onCompleted();
+ emitter.onComplete();
} else {
- subscriber.onError(new NetworkConnectionException());
+ emitter.onError(new NetworkConnectionException());
}
} catch (Exception e) {
- subscriber.onError(new NetworkConnectionException(e.getCause()));
+ emitter.onError(new NetworkConnectionException(e.getCause()));
}
} else {
- subscriber.onError(new NetworkConnectionException());
+ emitter.onError(new NetworkConnectionException());
}
});
}
- @RxLogObservable
@Override public Observable userEntityById(final int userId) {
- return Observable.create(subscriber -> {
+ return Observable.create(emitter -> {
if (isThereInternetConnection()) {
try {
String responseUserDetails = getUserDetailsFromApi(userId);
if (responseUserDetails != null) {
- subscriber.onNext(userEntityJsonMapper.transformUserEntity(responseUserDetails));
- subscriber.onCompleted();
+ emitter.onNext(userEntityJsonMapper.transformUserEntity(responseUserDetails));
+ emitter.onComplete();
} else {
- subscriber.onError(new NetworkConnectionException());
+ emitter.onError(new NetworkConnectionException());
}
} catch (Exception e) {
- subscriber.onError(new NetworkConnectionException(e.getCause()));
+ emitter.onError(new NetworkConnectionException(e.getCause()));
}
} else {
- subscriber.onError(new NetworkConnectionException());
+ emitter.onError(new NetworkConnectionException());
}
});
}
private String getUserEntitiesFromApi() throws MalformedURLException {
- return ApiConnection.createGET(RestApi.API_URL_GET_USER_LIST).requestSyncCall();
+ return ApiConnection.createGET(API_URL_GET_USER_LIST).requestSyncCall();
}
private String getUserDetailsFromApi(int userId) throws MalformedURLException {
- String apiUrl = RestApi.API_URL_GET_USER_DETAILS + userId + ".json";
+ String apiUrl = API_URL_GET_USER_DETAILS + userId + ".json";
return ApiConnection.createGET(apiUrl).requestSyncCall();
}
diff --git a/data/src/main/java/com/fernandocejas/android10/sample/data/repository/UserDataRepository.java b/data/src/main/java/com/fernandocejas/android10/sample/data/repository/UserDataRepository.java
index 24f125fd..edb0de0a 100644
--- a/data/src/main/java/com/fernandocejas/android10/sample/data/repository/UserDataRepository.java
+++ b/data/src/main/java/com/fernandocejas/android10/sample/data/repository/UserDataRepository.java
@@ -20,10 +20,10 @@
import com.fernandocejas.android10.sample.data.repository.datasource.UserDataStoreFactory;
import com.fernandocejas.android10.sample.domain.User;
import com.fernandocejas.android10.sample.domain.repository.UserRepository;
+import io.reactivex.Observable;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
-import rx.Observable;
/**
* {@link UserRepository} for retrieving user data.
@@ -41,24 +41,20 @@ public class UserDataRepository implements UserRepository {
* @param userEntityDataMapper {@link UserEntityDataMapper}.
*/
@Inject
- public UserDataRepository(UserDataStoreFactory dataStoreFactory,
+ UserDataRepository(UserDataStoreFactory dataStoreFactory,
UserEntityDataMapper userEntityDataMapper) {
this.userDataStoreFactory = dataStoreFactory;
this.userEntityDataMapper = userEntityDataMapper;
}
- @SuppressWarnings("Convert2MethodRef")
@Override public Observable> users() {
//we always get all users from the cloud
final UserDataStore userDataStore = this.userDataStoreFactory.createCloudDataStore();
- return userDataStore.userEntityList()
- .map(userEntities -> this.userEntityDataMapper.transform(userEntities));
+ return userDataStore.userEntityList().map(this.userEntityDataMapper::transform);
}
- @SuppressWarnings("Convert2MethodRef")
@Override public Observable user(int userId) {
final UserDataStore userDataStore = this.userDataStoreFactory.create(userId);
- return userDataStore.userEntityDetails(userId)
- .map(userEntity -> this.userEntityDataMapper.transform(userEntity));
+ return userDataStore.userEntityDetails(userId).map(this.userEntityDataMapper::transform);
}
}
diff --git a/data/src/main/java/com/fernandocejas/android10/sample/data/repository/datasource/CloudUserDataStore.java b/data/src/main/java/com/fernandocejas/android10/sample/data/repository/datasource/CloudUserDataStore.java
index 579995bd..e681ecd7 100644
--- a/data/src/main/java/com/fernandocejas/android10/sample/data/repository/datasource/CloudUserDataStore.java
+++ b/data/src/main/java/com/fernandocejas/android10/sample/data/repository/datasource/CloudUserDataStore.java
@@ -18,31 +18,24 @@
import com.fernandocejas.android10.sample.data.cache.UserCache;
import com.fernandocejas.android10.sample.data.entity.UserEntity;
import com.fernandocejas.android10.sample.data.net.RestApi;
+import io.reactivex.Observable;
import java.util.List;
-import rx.Observable;
-import rx.functions.Action1;
/**
* {@link UserDataStore} implementation based on connections to the api (Cloud).
*/
-public class CloudUserDataStore implements UserDataStore {
+class CloudUserDataStore implements UserDataStore {
private final RestApi restApi;
private final UserCache userCache;
- private final Action1 saveToCacheAction = userEntity -> {
- if (userEntity != null) {
- CloudUserDataStore.this.userCache.put(userEntity);
- }
- };
-
/**
* Construct a {@link UserDataStore} based on connections to the api (Cloud).
*
* @param restApi The {@link RestApi} implementation to use.
* @param userCache A {@link UserCache} to cache data retrieved from the api.
*/
- public CloudUserDataStore(RestApi restApi, UserCache userCache) {
+ CloudUserDataStore(RestApi restApi, UserCache userCache) {
this.restApi = restApi;
this.userCache = userCache;
}
@@ -52,6 +45,6 @@ public CloudUserDataStore(RestApi restApi, UserCache userCache) {
}
@Override public Observable userEntityDetails(final int userId) {
- return this.restApi.userEntityById(userId).doOnNext(saveToCacheAction);
+ return this.restApi.userEntityById(userId).doOnNext(CloudUserDataStore.this.userCache::put);
}
}
diff --git a/data/src/main/java/com/fernandocejas/android10/sample/data/repository/datasource/DiskUserDataStore.java b/data/src/main/java/com/fernandocejas/android10/sample/data/repository/datasource/DiskUserDataStore.java
index 5c5aaae2..d638032c 100644
--- a/data/src/main/java/com/fernandocejas/android10/sample/data/repository/datasource/DiskUserDataStore.java
+++ b/data/src/main/java/com/fernandocejas/android10/sample/data/repository/datasource/DiskUserDataStore.java
@@ -17,13 +17,13 @@
import com.fernandocejas.android10.sample.data.cache.UserCache;
import com.fernandocejas.android10.sample.data.entity.UserEntity;
+import io.reactivex.Observable;
import java.util.List;
-import rx.Observable;
/**
* {@link UserDataStore} implementation based on file system data store.
*/
-public class DiskUserDataStore implements UserDataStore {
+class DiskUserDataStore implements UserDataStore {
private final UserCache userCache;
@@ -32,7 +32,7 @@ public class DiskUserDataStore implements UserDataStore {
*
* @param userCache A {@link UserCache} to cache data retrieved from the api.
*/
- public DiskUserDataStore(UserCache userCache) {
+ DiskUserDataStore(UserCache userCache) {
this.userCache = userCache;
}
diff --git a/data/src/main/java/com/fernandocejas/android10/sample/data/repository/datasource/UserDataStore.java b/data/src/main/java/com/fernandocejas/android10/sample/data/repository/datasource/UserDataStore.java
index 744bae1e..ac4f9fbc 100644
--- a/data/src/main/java/com/fernandocejas/android10/sample/data/repository/datasource/UserDataStore.java
+++ b/data/src/main/java/com/fernandocejas/android10/sample/data/repository/datasource/UserDataStore.java
@@ -16,20 +16,20 @@
package com.fernandocejas.android10.sample.data.repository.datasource;
import com.fernandocejas.android10.sample.data.entity.UserEntity;
+import io.reactivex.Observable;
import java.util.List;
-import rx.Observable;
/**
* Interface that represents a data store from where data is retrieved.
*/
public interface UserDataStore {
/**
- * Get an {@link rx.Observable} which will emit a List of {@link UserEntity}.
+ * Get an {@link Observable} which will emit a List of {@link UserEntity}.
*/
Observable> userEntityList();
/**
- * Get an {@link rx.Observable} which will emit a {@link UserEntity} by its id.
+ * Get an {@link Observable} which will emit a {@link UserEntity} by its id.
*
* @param userId The id to retrieve user data.
*/
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 59e397e1..defc85df 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
@@ -16,6 +16,7 @@
package com.fernandocejas.android10.sample.data.repository.datasource;
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.net.RestApi;
@@ -33,10 +34,7 @@ public class UserDataStoreFactory {
private final UserCache userCache;
@Inject
- public UserDataStoreFactory(Context context, UserCache userCache) {
- if (context == null || userCache == null) {
- throw new IllegalArgumentException("Constructor parameters cannot be null!!!");
- }
+ UserDataStoreFactory(@NonNull Context context, @NonNull UserCache userCache) {
this.context = context.getApplicationContext();
this.userCache = userCache;
}
@@ -60,8 +58,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);
+ final UserEntityJsonMapper userEntityJsonMapper = new UserEntityJsonMapper();
+ final RestApi restApi = new RestApiImpl(this.context, userEntityJsonMapper);
return new CloudUserDataStore(restApi, this.userCache);
}
diff --git a/data/src/test/java/com/fernandocejas/android10/sample/data/ApplicationTestCase.java b/data/src/test/java/com/fernandocejas/android10/sample/data/ApplicationTestCase.java
index 72c06075..d8426bcb 100644
--- a/data/src/test/java/com/fernandocejas/android10/sample/data/ApplicationTestCase.java
+++ b/data/src/test/java/com/fernandocejas/android10/sample/data/ApplicationTestCase.java
@@ -5,7 +5,7 @@
* 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
+ * 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,
@@ -15,14 +15,34 @@
*/
package com.fernandocejas.android10.sample.data;
+import android.content.Context;
+import java.io.File;
+import org.junit.Rule;
+import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
-import org.robolectric.RobolectricGradleTestRunner;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
/**
* Base class for Robolectric data layer tests.
* Inherit from this class to create a test.
*/
-@RunWith(RobolectricGradleTestRunner.class)
-@Config(constants = BuildConfig.class, application = ApplicationStub.class)
-public abstract class ApplicationTestCase {}
+@RunWith(RobolectricTestRunner.class)
+@Config(constants = BuildConfig.class, application = ApplicationStub.class, sdk = 21)
+public abstract class ApplicationTestCase {
+
+ @Rule public TestRule injectMocksRule = (base, description) -> {
+ MockitoAnnotations.initMocks(ApplicationTestCase.this);
+ return base;
+ };
+
+ public static Context context() {
+ return RuntimeEnvironment.application;
+ }
+
+ public static File cacheDir() {
+ return RuntimeEnvironment.application.getCacheDir();
+ }
+}
diff --git a/data/src/test/java/com/fernandocejas/android10/sample/data/cache/FileManagerTest.java b/data/src/test/java/com/fernandocejas/android10/sample/data/cache/FileManagerTest.java
index f71f8a8f..8f0cb488 100644
--- a/data/src/test/java/com/fernandocejas/android10/sample/data/cache/FileManagerTest.java
+++ b/data/src/test/java/com/fernandocejas/android10/sample/data/cache/FileManagerTest.java
@@ -20,7 +20,6 @@
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.robolectric.RuntimeEnvironment;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
@@ -29,18 +28,16 @@
public class FileManagerTest extends ApplicationTestCase {
private FileManager fileManager;
- private File cacheDir;
@Before
public void setUp() {
fileManager = new FileManager();
- cacheDir = RuntimeEnvironment.application.getCacheDir();
}
@After
public void tearDown() {
- if (cacheDir != null) {
- fileManager.clearDirectory(cacheDir);
+ if (cacheDir() != null) {
+ fileManager.clearDirectory(cacheDir());
}
}
@@ -66,9 +63,7 @@ public void testFileContent() {
}
private File createDummyFile() {
- String dummyFilePath = cacheDir.getPath() + File.separator + "dumyFile";
- File dummyFile = new File(dummyFilePath);
-
- return dummyFile;
+ String dummyFilePath = cacheDir().getPath() + File.separator + "dummyFile";
+ return new File(dummyFilePath);
}
}
diff --git a/data/src/test/java/com/fernandocejas/android10/sample/data/cache/serializer/JsonSerializerTest.java b/data/src/test/java/com/fernandocejas/android10/sample/data/cache/serializer/SerializerTest.java
similarity index 79%
rename from data/src/test/java/com/fernandocejas/android10/sample/data/cache/serializer/JsonSerializerTest.java
rename to data/src/test/java/com/fernandocejas/android10/sample/data/cache/serializer/SerializerTest.java
index da15891a..d55bd3c3 100644
--- a/data/src/test/java/com/fernandocejas/android10/sample/data/cache/serializer/JsonSerializerTest.java
+++ b/data/src/test/java/com/fernandocejas/android10/sample/data/cache/serializer/SerializerTest.java
@@ -15,16 +15,18 @@
*/
package com.fernandocejas.android10.sample.data.cache.serializer;
-import com.fernandocejas.android10.sample.data.ApplicationTestCase;
import com.fernandocejas.android10.sample.data.entity.UserEntity;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
-public class JsonSerializerTest extends ApplicationTestCase {
+@RunWith(MockitoJUnitRunner.class)
+public class SerializerTest {
private static final String JSON_RESPONSE = "{\n"
+ " \"id\": 1,\n"
@@ -35,18 +37,18 @@ public class JsonSerializerTest extends ApplicationTestCase {
+ " \"email\": \"jcooper@babbleset.edu\"\n"
+ "}";
- private JsonSerializer jsonSerializer;
+ private Serializer serializer;
@Before
public void setUp() {
- jsonSerializer = new JsonSerializer();
+ serializer = new Serializer();
}
@Test
public void testSerializeHappyCase() {
- UserEntity userEntityOne = jsonSerializer.deserialize(JSON_RESPONSE);
- String jsonString = jsonSerializer.serialize(userEntityOne);
- UserEntity userEntityTwo = jsonSerializer.deserialize(jsonString);
+ final UserEntity userEntityOne = serializer.deserialize(JSON_RESPONSE, UserEntity.class);
+ final String jsonString = serializer.serialize(userEntityOne, UserEntity.class);
+ final UserEntity userEntityTwo = serializer.deserialize(jsonString, UserEntity.class);
assertThat(userEntityOne.getUserId(), is(userEntityTwo.getUserId()));
assertThat(userEntityOne.getFullname(), is(equalTo(userEntityTwo.getFullname())));
@@ -55,7 +57,7 @@ public void testSerializeHappyCase() {
@Test
public void testDesearializeHappyCase() {
- UserEntity userEntity = jsonSerializer.deserialize(JSON_RESPONSE);
+ final UserEntity userEntity = serializer.deserialize(JSON_RESPONSE, UserEntity.class);
assertThat(userEntity.getUserId(), is(1));
assertThat(userEntity.getFullname(), is("Simon Hill"));
diff --git a/data/src/test/java/com/fernandocejas/android10/sample/data/entity/mapper/UserEntityDataMapperTest.java b/data/src/test/java/com/fernandocejas/android10/sample/data/entity/mapper/UserEntityDataMapperTest.java
index 19a4db56..963d28e6 100644
--- a/data/src/test/java/com/fernandocejas/android10/sample/data/entity/mapper/UserEntityDataMapperTest.java
+++ b/data/src/test/java/com/fernandocejas/android10/sample/data/entity/mapper/UserEntityDataMapperTest.java
@@ -15,7 +15,6 @@
*/
package com.fernandocejas.android10.sample.data.entity.mapper;
-import com.fernandocejas.android10.sample.data.ApplicationTestCase;
import com.fernandocejas.android10.sample.data.entity.UserEntity;
import com.fernandocejas.android10.sample.domain.User;
import java.util.ArrayList;
@@ -23,13 +22,16 @@
import java.util.List;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.mock;
-public class UserEntityDataMapperTest extends ApplicationTestCase {
+@RunWith(MockitoJUnitRunner.class)
+public class UserEntityDataMapperTest {
private static final int FAKE_USER_ID = 123;
private static final String FAKE_FULLNAME = "Tony Stark";
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/UserEntityJsonMapperTest.java
index f834f52d..a6eb3fcc 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/UserEntityJsonMapperTest.java
@@ -15,7 +15,6 @@
*/
package com.fernandocejas.android10.sample.data.entity.mapper;
-import com.fernandocejas.android10.sample.data.ApplicationTestCase;
import com.fernandocejas.android10.sample.data.entity.UserEntity;
import com.google.gson.JsonSyntaxException;
import java.util.Collection;
@@ -23,12 +22,15 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.mockito.runners.MockitoJUnitRunner;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
-public class UserEntityJsonMapperTest extends ApplicationTestCase {
+@RunWith(MockitoJUnitRunner.class)
+public class UserEntityJsonMapperTest {
private static final String JSON_RESPONSE_USER_DETAILS = "{\n"
+ " \"id\": 1,\n"
diff --git a/data/src/test/java/com/fernandocejas/android10/sample/data/exception/RepositoryErrorBundleTest.java b/data/src/test/java/com/fernandocejas/android10/sample/data/exception/RepositoryErrorBundleTest.java
index 277f7ad7..d2f3d697 100644
--- a/data/src/test/java/com/fernandocejas/android10/sample/data/exception/RepositoryErrorBundleTest.java
+++ b/data/src/test/java/com/fernandocejas/android10/sample/data/exception/RepositoryErrorBundleTest.java
@@ -15,28 +15,28 @@
*/
package com.fernandocejas.android10.sample.data.exception;
-import com.fernandocejas.android10.sample.data.ApplicationTestCase;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.runners.MockitoJUnitRunner;
import static org.mockito.Mockito.verify;
-public class RepositoryErrorBundleTest extends ApplicationTestCase {
+@RunWith(MockitoJUnitRunner.class)
+public class RepositoryErrorBundleTest {
private RepositoryErrorBundle repositoryErrorBundle;
- @Mock
- private Exception mockException;
+ @Mock private Exception mockException;
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
repositoryErrorBundle = new RepositoryErrorBundle(mockException);
}
@Test
+ @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
public void testGetErrorMessageInteraction() {
repositoryErrorBundle.getErrorMessage();
diff --git a/data/src/test/java/com/fernandocejas/android10/sample/data/repository/UserDataRepositoryTest.java b/data/src/test/java/com/fernandocejas/android10/sample/data/repository/UserDataRepositoryTest.java
index 70752055..1eac1d06 100644
--- a/data/src/test/java/com/fernandocejas/android10/sample/data/repository/UserDataRepositoryTest.java
+++ b/data/src/test/java/com/fernandocejas/android10/sample/data/repository/UserDataRepositoryTest.java
@@ -15,27 +15,26 @@
*/
package com.fernandocejas.android10.sample.data.repository;
-import com.fernandocejas.android10.sample.data.ApplicationTestCase;
import com.fernandocejas.android10.sample.data.entity.UserEntity;
import com.fernandocejas.android10.sample.data.entity.mapper.UserEntityDataMapper;
import com.fernandocejas.android10.sample.data.repository.datasource.UserDataStore;
import com.fernandocejas.android10.sample.data.repository.datasource.UserDataStoreFactory;
import com.fernandocejas.android10.sample.domain.User;
+import io.reactivex.Observable;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import rx.Observable;
+import org.mockito.runners.MockitoJUnitRunner;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.verify;
-public class UserDataRepositoryTest extends ApplicationTestCase {
+@RunWith(MockitoJUnitRunner.class)
+public class UserDataRepositoryTest {
private static final int FAKE_USER_ID = 123;
@@ -47,15 +46,9 @@ public class UserDataRepositoryTest extends ApplicationTestCase {
@Mock private UserEntity mockUserEntity;
@Mock private User mockUser;
- @Rule
- public ExpectedException expectedException = ExpectedException.none();
-
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
- userDataRepository = new UserDataRepository(mockUserDataStoreFactory,
- mockUserEntityDataMapper);
-
+ userDataRepository = new UserDataRepository(mockUserDataStoreFactory, mockUserEntityDataMapper);
given(mockUserDataStoreFactory.create(anyInt())).willReturn(mockUserDataStore);
given(mockUserDataStoreFactory.createCloudDataStore()).willReturn(mockUserDataStore);
}
diff --git a/data/src/test/java/com/fernandocejas/android10/sample/data/repository/datasource/CloudUserDataStoreTest.java b/data/src/test/java/com/fernandocejas/android10/sample/data/repository/datasource/CloudUserDataStoreTest.java
index b54e58e1..a47a2e4e 100644
--- a/data/src/test/java/com/fernandocejas/android10/sample/data/repository/datasource/CloudUserDataStoreTest.java
+++ b/data/src/test/java/com/fernandocejas/android10/sample/data/repository/datasource/CloudUserDataStoreTest.java
@@ -15,20 +15,21 @@
*/
package com.fernandocejas.android10.sample.data.repository.datasource;
-import com.fernandocejas.android10.sample.data.ApplicationTestCase;
import com.fernandocejas.android10.sample.data.cache.UserCache;
import com.fernandocejas.android10.sample.data.entity.UserEntity;
import com.fernandocejas.android10.sample.data.net.RestApi;
+import io.reactivex.Observable;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import rx.Observable;
+import org.mockito.runners.MockitoJUnitRunner;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.verify;
-public class CloudUserDataStoreTest extends ApplicationTestCase {
+@RunWith(MockitoJUnitRunner.class)
+public class CloudUserDataStoreTest {
private static final int FAKE_USER_ID = 765;
@@ -39,7 +40,6 @@ public class CloudUserDataStoreTest extends ApplicationTestCase {
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
cloudUserDataStore = new CloudUserDataStore(mockRestApi, mockUserCache);
}
diff --git a/data/src/test/java/com/fernandocejas/android10/sample/data/repository/datasource/DiskUserDataStoreTest.java b/data/src/test/java/com/fernandocejas/android10/sample/data/repository/datasource/DiskUserDataStoreTest.java
index 6c7bca5d..6a649142 100644
--- a/data/src/test/java/com/fernandocejas/android10/sample/data/repository/datasource/DiskUserDataStoreTest.java
+++ b/data/src/test/java/com/fernandocejas/android10/sample/data/repository/datasource/DiskUserDataStoreTest.java
@@ -15,18 +15,19 @@
*/
package com.fernandocejas.android10.sample.data.repository.datasource;
-import com.fernandocejas.android10.sample.data.ApplicationTestCase;
import com.fernandocejas.android10.sample.data.cache.UserCache;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.runners.MockitoJUnitRunner;
import static org.mockito.Mockito.verify;
-public class DiskUserDataStoreTest extends ApplicationTestCase {
+@RunWith(MockitoJUnitRunner.class)
+public class DiskUserDataStoreTest {
private static final int FAKE_USER_ID = 11;
@@ -38,7 +39,6 @@ public class DiskUserDataStoreTest extends ApplicationTestCase {
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
diskUserDataStore = new DiskUserDataStore(mockUserCache);
}
diff --git a/data/src/test/java/com/fernandocejas/android10/sample/data/repository/datasource/UserDataStoreFactoryTest.java b/data/src/test/java/com/fernandocejas/android10/sample/data/repository/datasource/UserDataStoreFactoryTest.java
index b8c644a4..6c560a0a 100644
--- a/data/src/test/java/com/fernandocejas/android10/sample/data/repository/datasource/UserDataStoreFactoryTest.java
+++ b/data/src/test/java/com/fernandocejas/android10/sample/data/repository/datasource/UserDataStoreFactoryTest.java
@@ -20,7 +20,6 @@
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import static org.hamcrest.CoreMatchers.instanceOf;
@@ -36,14 +35,11 @@ public class UserDataStoreFactoryTest extends ApplicationTestCase {
private UserDataStoreFactory userDataStoreFactory;
- @Mock
- private UserCache mockUserCache;
+ @Mock private UserCache mockUserCache;
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
- userDataStoreFactory =
- new UserDataStoreFactory(RuntimeEnvironment.application, mockUserCache);
+ userDataStoreFactory = new UserDataStoreFactory(RuntimeEnvironment.application, mockUserCache);
}
@Test
diff --git a/domain/build.gradle b/domain/build.gradle
index e9c9e8c6..f647f20c 100644
--- a/domain/build.gradle
+++ b/domain/build.gradle
@@ -19,12 +19,13 @@ dependencies {
def domainDependencies = rootProject.ext.domainDependencies
def domainTestDependencies = rootProject.ext.domainTestDependencies
- provided domainDependencies.daggerCompiler
- provided domainDependencies.javaxAnnotation
+ compileOnly domainDependencies.javaxAnnotation
- compile domainDependencies.dagger
- compile domainDependencies.rxJava
+ implementation domainDependencies.javaxInject
+ implementation domainDependencies.rxJava
+ compile domainDependencies.arrow
- testCompile domainTestDependencies.junit
- testCompile domainTestDependencies.mockito
-}
\ No newline at end of file
+ testImplementation domainTestDependencies.junit
+ testImplementation domainTestDependencies.mockito
+ testImplementation domainTestDependencies.assertj
+}
diff --git a/domain/src/main/java/com/fernandocejas/android10/sample/domain/User.java b/domain/src/main/java/com/fernandocejas/android10/sample/domain/User.java
index d62a021d..21bf5378 100644
--- a/domain/src/main/java/com/fernandocejas/android10/sample/domain/User.java
+++ b/domain/src/main/java/com/fernandocejas/android10/sample/domain/User.java
@@ -75,19 +75,4 @@ public int getFollowers() {
public void setFollowers(int followers) {
this.followers = followers;
}
-
- @Override public String toString() {
- StringBuilder stringBuilder = new StringBuilder();
-
- stringBuilder.append("***** User Details *****\n");
- stringBuilder.append("id=" + this.getUserId() + "\n");
- stringBuilder.append("cover url=" + this.getCoverUrl() + "\n");
- stringBuilder.append("fullname=" + this.getFullName() + "\n");
- stringBuilder.append("email=" + this.getEmail() + "\n");
- stringBuilder.append("description=" + this.getDescription() + "\n");
- stringBuilder.append("followers=" + this.getFollowers() + "\n");
- stringBuilder.append("*******************************");
-
- return stringBuilder.toString();
- }
}
diff --git a/domain/src/main/java/com/fernandocejas/android10/sample/domain/executor/PostExecutionThread.java b/domain/src/main/java/com/fernandocejas/android10/sample/domain/executor/PostExecutionThread.java
index a69f2859..6ed498cb 100644
--- a/domain/src/main/java/com/fernandocejas/android10/sample/domain/executor/PostExecutionThread.java
+++ b/domain/src/main/java/com/fernandocejas/android10/sample/domain/executor/PostExecutionThread.java
@@ -15,7 +15,7 @@
*/
package com.fernandocejas.android10.sample.domain.executor;
-import rx.Scheduler;
+import io.reactivex.Scheduler;
/**
* Thread abstraction created to change the execution context from any thread to any other thread.
diff --git a/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/DefaultSubscriber.java b/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/DefaultObserver.java
similarity index 72%
rename from domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/DefaultSubscriber.java
rename to domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/DefaultObserver.java
index 81abea5c..4bcd3e49 100644
--- a/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/DefaultSubscriber.java
+++ b/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/DefaultObserver.java
@@ -15,19 +15,21 @@
*/
package com.fernandocejas.android10.sample.domain.interactor;
+import io.reactivex.observers.DisposableObserver;
+
/**
- * Default subscriber base class to be used whenever you want default error handling.
+ * Default {@link DisposableObserver} base class to be used whenever you want default error handling.
*/
-public class DefaultSubscriber extends rx.Subscriber {
- @Override public void onCompleted() {
+public class DefaultObserver extends DisposableObserver {
+ @Override public void onNext(T t) {
// no-op by default.
}
- @Override public void onError(Throwable e) {
+ @Override public void onComplete() {
// no-op by default.
}
- @Override public void onNext(T t) {
+ @Override public void onError(Throwable exception) {
// no-op by default.
}
}
diff --git a/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/GetUserDetails.java b/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/GetUserDetails.java
index 134fc4d0..377d0c1d 100644
--- a/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/GetUserDetails.java
+++ b/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/GetUserDetails.java
@@ -19,27 +19,40 @@
import com.fernandocejas.android10.sample.domain.executor.PostExecutionThread;
import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
import com.fernandocejas.android10.sample.domain.repository.UserRepository;
+import com.fernandocejas.arrow.checks.Preconditions;
+import io.reactivex.Observable;
import javax.inject.Inject;
-import rx.Observable;
/**
* This class is an implementation of {@link UseCase} that represents a use case for
* retrieving data related to an specific {@link User}.
*/
-public class GetUserDetails extends UseCase {
+public class GetUserDetails extends UseCase {
- private final int userId;
private final UserRepository userRepository;
@Inject
- public GetUserDetails(int userId, UserRepository userRepository,
- ThreadExecutor threadExecutor, PostExecutionThread postExecutionThread) {
+ GetUserDetails(UserRepository userRepository, ThreadExecutor threadExecutor,
+ PostExecutionThread postExecutionThread) {
super(threadExecutor, postExecutionThread);
- this.userId = userId;
this.userRepository = userRepository;
}
- @Override protected Observable buildUseCaseObservable() {
- return this.userRepository.user(this.userId);
+ @Override Observable buildUseCaseObservable(Params params) {
+ Preconditions.checkNotNull(params);
+ return this.userRepository.user(params.userId);
+ }
+
+ public static final class Params {
+
+ private final int userId;
+
+ private Params(int userId) {
+ this.userId = userId;
+ }
+
+ public static Params forUser(int userId) {
+ return new Params(userId);
+ }
}
}
diff --git a/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/GetUserList.java b/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/GetUserList.java
index 0780ff3d..e43ce75e 100644
--- a/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/GetUserList.java
+++ b/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/GetUserList.java
@@ -19,25 +19,26 @@
import com.fernandocejas.android10.sample.domain.executor.PostExecutionThread;
import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
import com.fernandocejas.android10.sample.domain.repository.UserRepository;
+import io.reactivex.Observable;
+import java.util.List;
import javax.inject.Inject;
-import rx.Observable;
/**
* This class is an implementation of {@link UseCase} that represents a use case for
* retrieving a collection of all {@link User}.
*/
-public class GetUserList extends UseCase {
+public class GetUserList extends UseCase, Void> {
private final UserRepository userRepository;
@Inject
- public GetUserList(UserRepository userRepository, ThreadExecutor threadExecutor,
+ GetUserList(UserRepository userRepository, ThreadExecutor threadExecutor,
PostExecutionThread postExecutionThread) {
super(threadExecutor, postExecutionThread);
this.userRepository = userRepository;
}
- @Override public Observable buildUseCaseObservable() {
+ @Override Observable> buildUseCaseObservable(Void unused) {
return this.userRepository.users();
}
}
diff --git a/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/UseCase.java b/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/UseCase.java
index 24e9d010..e71f9145 100644
--- a/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/UseCase.java
+++ b/domain/src/main/java/com/fernandocejas/android10/sample/domain/interactor/UseCase.java
@@ -17,58 +17,68 @@
import com.fernandocejas.android10.sample.domain.executor.PostExecutionThread;
import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
-import rx.Subscriber;
-import rx.Observable;
-import rx.Subscription;
-import rx.schedulers.Schedulers;
-import rx.subscriptions.Subscriptions;
+import com.fernandocejas.arrow.checks.Preconditions;
+import io.reactivex.Observable;
+import io.reactivex.disposables.CompositeDisposable;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.observers.DisposableObserver;
+import io.reactivex.schedulers.Schedulers;
/**
* Abstract class for a Use Case (Interactor in terms of Clean Architecture).
* This interface represents a execution unit for different use cases (this means any use case
* in the application should implement this contract).
*
- * By convention each UseCase implementation will return the result using a {@link rx.Subscriber}
+ * By convention each UseCase implementation will return the result using a {@link DisposableObserver}
* that will execute its job in a background thread and will post the result in the UI thread.
*/
-public abstract class UseCase {
+public abstract class UseCase {
private final ThreadExecutor threadExecutor;
private final PostExecutionThread postExecutionThread;
+ private final CompositeDisposable disposables;
- private Subscription subscription = Subscriptions.empty();
-
- protected UseCase(ThreadExecutor threadExecutor,
- PostExecutionThread postExecutionThread) {
+ UseCase(ThreadExecutor threadExecutor, PostExecutionThread postExecutionThread) {
this.threadExecutor = threadExecutor;
this.postExecutionThread = postExecutionThread;
+ this.disposables = new CompositeDisposable();
}
/**
- * Builds an {@link rx.Observable} which will be used when executing the current {@link UseCase}.
+ * Builds an {@link Observable} which will be used when executing the current {@link UseCase}.
*/
- protected abstract Observable buildUseCaseObservable();
+ abstract Observable buildUseCaseObservable(Params params);
/**
* Executes the current use case.
*
- * @param UseCaseSubscriber The guy who will be listen to the observable build
- * with {@link #buildUseCaseObservable()}.
+ * @param observer {@link DisposableObserver} which will be listening to the observable build
+ * by {@link #buildUseCaseObservable(Params)} ()} method.
+ * @param params Parameters (Optional) used to build/execute this use case.
*/
- @SuppressWarnings("unchecked")
- public void execute(Subscriber UseCaseSubscriber) {
- this.subscription = this.buildUseCaseObservable()
+ public void execute(DisposableObserver observer, Params params) {
+ Preconditions.checkNotNull(observer);
+ final Observable observable = this.buildUseCaseObservable(params)
.subscribeOn(Schedulers.from(threadExecutor))
- .observeOn(postExecutionThread.getScheduler())
- .subscribe(UseCaseSubscriber);
+ .observeOn(postExecutionThread.getScheduler());
+ addDisposable(observable.subscribeWith(observer));
}
/**
- * Unsubscribes from current {@link rx.Subscription}.
+ * Dispose from current {@link CompositeDisposable}.
*/
- public void unsubscribe() {
- if (!subscription.isUnsubscribed()) {
- subscription.unsubscribe();
+ public void dispose() {
+ if (!disposables.isDisposed()) {
+ disposables.dispose();
}
}
+
+ /**
+ * Dispose from current {@link CompositeDisposable}.
+ */
+ private void addDisposable(Disposable disposable) {
+ Preconditions.checkNotNull(disposable);
+ Preconditions.checkNotNull(disposables);
+ disposables.add(disposable);
+ }
}
diff --git a/domain/src/main/java/com/fernandocejas/android10/sample/domain/repository/UserRepository.java b/domain/src/main/java/com/fernandocejas/android10/sample/domain/repository/UserRepository.java
index 69c40a03..29362a00 100644
--- a/domain/src/main/java/com/fernandocejas/android10/sample/domain/repository/UserRepository.java
+++ b/domain/src/main/java/com/fernandocejas/android10/sample/domain/repository/UserRepository.java
@@ -16,20 +16,20 @@
package com.fernandocejas.android10.sample.domain.repository;
import com.fernandocejas.android10.sample.domain.User;
+import io.reactivex.Observable;
import java.util.List;
-import rx.Observable;
/**
* Interface that represents a Repository for getting {@link User} related data.
*/
public interface UserRepository {
/**
- * Get an {@link rx.Observable} which will emit a List of {@link User}.
+ * Get an {@link Observable} which will emit a List of {@link User}.
*/
Observable> users();
/**
- * Get an {@link rx.Observable} which will emit a {@link User}.
+ * Get an {@link Observable} which will emit a {@link User}.
*
* @param userId The user id used to retrieve user data.
*/
diff --git a/domain/src/test/java/com/fernandocejas/android10/sample/domain/UserTest.java b/domain/src/test/java/com/fernandocejas/android10/sample/domain/UserTest.java
index ea45784a..e321d410 100644
--- a/domain/src/test/java/com/fernandocejas/android10/sample/domain/UserTest.java
+++ b/domain/src/test/java/com/fernandocejas/android10/sample/domain/UserTest.java
@@ -18,8 +18,7 @@
import org.junit.Before;
import org.junit.Test;
-import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertThat;
+import static org.assertj.core.api.Assertions.assertThat;
public class UserTest {
@@ -34,8 +33,8 @@ public void setUp() {
@Test
public void testUserConstructorHappyCase() {
- int userId = user.getUserId();
+ final int userId = user.getUserId();
- assertThat(userId, is(FAKE_USER_ID));
+ assertThat(userId).isEqualTo(FAKE_USER_ID);
}
}
diff --git a/domain/src/test/java/com/fernandocejas/android10/sample/domain/exception/DefaultErrorBundleTest.java b/domain/src/test/java/com/fernandocejas/android10/sample/domain/exception/DefaultErrorBundleTest.java
index 1ba00434..0e33d6e8 100644
--- a/domain/src/test/java/com/fernandocejas/android10/sample/domain/exception/DefaultErrorBundleTest.java
+++ b/domain/src/test/java/com/fernandocejas/android10/sample/domain/exception/DefaultErrorBundleTest.java
@@ -5,7 +5,7 @@
* 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
+ * 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,
@@ -17,20 +17,20 @@
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.runners.MockitoJUnitRunner;
import static org.mockito.Mockito.verify;
+@RunWith(MockitoJUnitRunner.class)
public class DefaultErrorBundleTest {
private DefaultErrorBundle defaultErrorBundle;
- @Mock
- private Exception mockException;
+ @Mock private Exception mockException;
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
defaultErrorBundle = new DefaultErrorBundle(mockException);
}
@@ -40,4 +40,4 @@ public void testGetErrorMessageInteraction() {
verify(mockException).getMessage();
}
-}
\ No newline at end of file
+}
diff --git a/domain/src/test/java/com/fernandocejas/android10/sample/domain/interactor/GetUserDetailsTest.java b/domain/src/test/java/com/fernandocejas/android10/sample/domain/interactor/GetUserDetailsTest.java
index 8e730cb2..01baab94 100644
--- a/domain/src/test/java/com/fernandocejas/android10/sample/domain/interactor/GetUserDetailsTest.java
+++ b/domain/src/test/java/com/fernandocejas/android10/sample/domain/interactor/GetUserDetailsTest.java
@@ -17,19 +17,24 @@
import com.fernandocejas.android10.sample.domain.executor.PostExecutionThread;
import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
+import com.fernandocejas.android10.sample.domain.interactor.GetUserDetails.Params;
import com.fernandocejas.android10.sample.domain.repository.UserRepository;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.runners.MockitoJUnitRunner;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
+@RunWith(MockitoJUnitRunner.class)
public class GetUserDetailsTest {
- private static final int FAKE_USER_ID = 123;
+ private static final int USER_ID = 123;
private GetUserDetails getUserDetails;
@@ -37,20 +42,27 @@ public class GetUserDetailsTest {
@Mock private ThreadExecutor mockThreadExecutor;
@Mock private PostExecutionThread mockPostExecutionThread;
+ @Rule public ExpectedException expectedException = ExpectedException.none();
+
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
- getUserDetails = new GetUserDetails(FAKE_USER_ID, mockUserRepository,
- mockThreadExecutor, mockPostExecutionThread);
+ getUserDetails = new GetUserDetails(mockUserRepository, mockThreadExecutor,
+ mockPostExecutionThread);
}
@Test
public void testGetUserDetailsUseCaseObservableHappyCase() {
- getUserDetails.buildUseCaseObservable();
+ getUserDetails.buildUseCaseObservable(Params.forUser(USER_ID));
- verify(mockUserRepository).user(FAKE_USER_ID);
+ verify(mockUserRepository).user(USER_ID);
verifyNoMoreInteractions(mockUserRepository);
verifyZeroInteractions(mockPostExecutionThread);
verifyZeroInteractions(mockThreadExecutor);
}
+
+ @Test
+ public void testShouldFailWhenNoOrEmptyParameters() {
+ expectedException.expect(NullPointerException.class);
+ getUserDetails.buildUseCaseObservable(null);
+ }
}
diff --git a/domain/src/test/java/com/fernandocejas/android10/sample/domain/interactor/GetUserListTest.java b/domain/src/test/java/com/fernandocejas/android10/sample/domain/interactor/GetUserListTest.java
index 0e1565ff..13694063 100644
--- a/domain/src/test/java/com/fernandocejas/android10/sample/domain/interactor/GetUserListTest.java
+++ b/domain/src/test/java/com/fernandocejas/android10/sample/domain/interactor/GetUserListTest.java
@@ -20,13 +20,15 @@
import com.fernandocejas.android10.sample.domain.repository.UserRepository;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.runners.MockitoJUnitRunner;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
+@RunWith(MockitoJUnitRunner.class)
public class GetUserListTest {
private GetUserList getUserList;
@@ -37,14 +39,13 @@ public class GetUserListTest {
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
getUserList = new GetUserList(mockUserRepository, mockThreadExecutor,
mockPostExecutionThread);
}
@Test
public void testGetUserListUseCaseObservableHappyCase() {
- getUserList.buildUseCaseObservable();
+ getUserList.buildUseCaseObservable(null);
verify(mockUserRepository).users();
verifyNoMoreInteractions(mockUserRepository);
diff --git a/domain/src/test/java/com/fernandocejas/android10/sample/domain/interactor/UseCaseTest.java b/domain/src/test/java/com/fernandocejas/android10/sample/domain/interactor/UseCaseTest.java
index e8d20444..b8882001 100644
--- a/domain/src/test/java/com/fernandocejas/android10/sample/domain/interactor/UseCaseTest.java
+++ b/domain/src/test/java/com/fernandocejas/android10/sample/domain/interactor/UseCaseTest.java
@@ -17,68 +17,94 @@
import com.fernandocejas.android10.sample.domain.executor.PostExecutionThread;
import com.fernandocejas.android10.sample.domain.executor.ThreadExecutor;
+import io.reactivex.Observable;
+import io.reactivex.observers.DisposableObserver;
+import io.reactivex.schedulers.TestScheduler;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import rx.Observable;
-import rx.Subscriber;
-import rx.observers.TestSubscriber;
-import rx.schedulers.TestScheduler;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.core.Is.is;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
+@RunWith(MockitoJUnitRunner.class)
public class UseCaseTest {
private UseCaseTestClass useCase;
+ private TestDisposableObserver