diff --git a/ChangeLog.md b/ChangeLog.md
index e442bd3..66bbd8e 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,8 @@
+Version: 1.2.0
+* MvcGraph.inject throws runtime exception - MvcGraphException now. So no need to catch poke exceptions any more.
+* MvcGraph.get method to get an instance. It provides cached instance if there is already an existing one, otherwise the newly created instance.
+* Improve exception handling in library poke.
+
Version: 1.1.9
Fix bug
* When a recovering fragment in view pager its onViewReady is not called when its holding activity resume by popping out from another above activity.
diff --git a/README.md b/README.md
index c0a706a..2112f02 100644
--- a/README.md
+++ b/README.md
@@ -33,13 +33,13 @@ The library is currently release to jCenter and MavenCentral
com.shipdream
android-mvc
- 1.1.9
+ 1.2.0
```
**Gradle:**
```groovy
-compile "com.shipdream:android-mvc:1.1.9"
+compile "com.shipdream:android-mvc:1.2.0"
```
## Dependency injection with reference count
diff --git a/build.gradle b/build.gradle
index a831776..6c01d1d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -74,8 +74,8 @@ ext {
gitUrl = 'https://github.com/kejunxia/AndroidMvc.git' // Git repository URL
version = [
major: 1,
- minor: 1,
- patch : 9
+ minor: 2,
+ patch : 0
]
libGroup = 'com.shipdream'
libVersion = "${version.major}.${version.minor}.${version.patch}"
diff --git a/documents/sites/Site-MarkDown.md b/documents/sites/Site-MarkDown.md
index 38ac817..82a6c88 100644
--- a/documents/sites/Site-MarkDown.md
+++ b/documents/sites/Site-MarkDown.md
@@ -40,13 +40,13 @@ The library is currently release to jCenter and MavenCentral
com.shipdream
android-mvc
- 1.1.9
+ 1.2.0
```
**Gradle:**
```groovy
-compile "com.shipdream:android-mvc:1.1.9"
+compile "com.shipdream:android-mvc:1.2.0"
```
## Samples
diff --git a/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/MvcGraph.java b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/MvcGraph.java
index 5a53a5f..114b8cf 100644
--- a/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/MvcGraph.java
+++ b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/MvcGraph.java
@@ -27,7 +27,7 @@
import com.shipdream.lib.poke.Graph;
import com.shipdream.lib.poke.ImplClassLocator;
import com.shipdream.lib.poke.ImplClassLocatorByPattern;
-import com.shipdream.lib.poke.LocateClassException;
+import com.shipdream.lib.poke.ImplClassNotFoundException;
import com.shipdream.lib.poke.Provider;
import com.shipdream.lib.poke.ProviderByClassType;
import com.shipdream.lib.poke.ProviderFinderByRegistry;
@@ -171,15 +171,45 @@ public void clearOnProviderFreedListeners() {
graph.clearOnProviderFreedListeners();
}
+ /**
+ * Get an instance matching the type and qualifier. If there is an instance cached, the cached
+ * instance will be returned otherwise a new instance will be created.
+ *
+ *
Note that, not like {@link #inject(Object)} (Object)} this method will NOT increment
+ * reference count for the injectable object with the same type and qualifier.
+ * @param type the type of the object
+ * @param qualifier the qualifier of the injected object. Null is allowed if no qualifier is specified
+ * @return The cached object or a new instance matching the type and qualifier
+ * @throws MvcGraphException throw if exception occurs during getting the instance
+ */
+ public T get(Class type, Annotation qualifier) {
+ try {
+ return graph.get(type, qualifier, Inject.class);
+ } catch (ProviderMissingException e) {
+ throw new MvcGraphException(e.getMessage(), e);
+ } catch (ProvideException e) {
+ throw new MvcGraphException(e.getMessage(), e);
+ } catch (CircularDependenciesException e) {
+ throw new MvcGraphException(e.getMessage(), e);
+ }
+ }
+
/**
* Inject all fields annotated by {@link Inject}. References of controllers will be
* incremented.
*
* @param target The target object whose fields annotated by {@link Inject} will be injected.
- * @throws ProvideException
*/
- public void inject(Object target) throws ProvideException, CircularDependenciesException, ProviderMissingException {
- graph.inject(target, Inject.class);
+ public void inject(Object target) {
+ try {
+ graph.inject(target, Inject.class);
+ } catch (ProvideException e) {
+ throw new MvcGraphException(e.getMessage(), e);
+ } catch (ProviderMissingException e) {
+ throw new MvcGraphException(e.getMessage(), e);
+ } catch (CircularDependenciesException e) {
+ throw new MvcGraphException(e.getMessage(), e);
+ }
}
/**
@@ -190,7 +220,11 @@ public void inject(Object target) throws ProvideException, CircularDependenciesE
* @param target of which the object fields will be released.
*/
public void release(Object target) {
- graph.release(target, Inject.class);
+ try {
+ graph.release(target, Inject.class);
+ } catch (ProviderMissingException e) {
+ throw new MvcGraphException(e.getMessage(), e);
+ }
}
/**
@@ -326,7 +360,7 @@ private DefaultProviderFinder(MvcGraph mvcGraph) {
@SuppressWarnings("unchecked")
@Override
- public Provider findProvider(Class type, Annotation qualifier) {
+ public Provider findProvider(Class type, Annotation qualifier) throws ProviderMissingException {
Provider provider = super.findProvider(type, qualifier);
if (provider == null) {
provider = providers.get(type);
@@ -336,8 +370,8 @@ public Provider findProvider(Class type, Annotation qualifier) {
provider = new MvcProvider<>(mvcGraph.stateManagedObjects, type, impClass);
provider.setScopeCache(defaultImplClassLocator.getScopeCache());
providers.put(type, provider);
- } catch (LocateClassException e) {
- throw new RuntimeException(new ProviderMissingException(e.getMessage(), e));
+ } catch (ImplClassNotFoundException e) {
+ throw new ProviderMissingException(type, qualifier, e);
}
}
}
diff --git a/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/MvcGraphException.java b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/MvcGraphException.java
new file mode 100644
index 0000000..37e1289
--- /dev/null
+++ b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/MvcGraphException.java
@@ -0,0 +1,11 @@
+package com.shipdream.lib.android.mvc;
+
+public class MvcGraphException extends RuntimeException {
+ public MvcGraphException(String message) {
+ super(message);
+ }
+
+ public MvcGraphException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
\ No newline at end of file
diff --git a/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/event/BaseEvent.java b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/event/BaseEvent.java
index e2d6582..013025e 100644
--- a/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/event/BaseEvent.java
+++ b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/event/BaseEvent.java
@@ -17,7 +17,7 @@
package com.shipdream.lib.android.mvc.event;
public class BaseEvent {
- private Object sender;
+ private final Object sender;
public BaseEvent(Object sender) {
this.sender = sender;
diff --git a/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/event/ValueChangeEventC2C.java b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/event/ValueChangeEventC2C.java
index 9602031..850706e 100644
--- a/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/event/ValueChangeEventC2C.java
+++ b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/event/ValueChangeEventC2C.java
@@ -17,8 +17,8 @@
package com.shipdream.lib.android.mvc.event;
public class ValueChangeEventC2C extends BaseEventC2C{
- private T lastValue;
- private T currentValue;
+ private final T lastValue;
+ private final T currentValue;
public ValueChangeEventC2C(Object sender, T lastValue, T currentValue) {
super(sender);
diff --git a/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/event/ValueChangeEventC2V.java b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/event/ValueChangeEventC2V.java
index 576c5ca..edc250c 100644
--- a/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/event/ValueChangeEventC2V.java
+++ b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/event/ValueChangeEventC2V.java
@@ -17,8 +17,8 @@
package com.shipdream.lib.android.mvc.event;
public class ValueChangeEventC2V extends BaseEventC2V{
- private T lastValue;
- private T currentValue;
+ private final T lastValue;
+ private final T currentValue;
public ValueChangeEventC2V(Object sender, T lastValue, T currentValue) {
super(sender);
diff --git a/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/event/ValueChangeEventV2V.java b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/event/ValueChangeEventV2V.java
index 638507c..baa51c9 100644
--- a/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/event/ValueChangeEventV2V.java
+++ b/library/android-mvc-controller/src/main/java/com/shipdream/lib/android/mvc/event/ValueChangeEventV2V.java
@@ -17,8 +17,8 @@
package com.shipdream.lib.android.mvc.event;
public class ValueChangeEventV2V extends BaseEventV2V{
- private T lastValue;
- private T currentValue;
+ private final T lastValue;
+ private final T currentValue;
public ValueChangeEventV2V(Object sender, T lastValue, T currentValue) {
super(sender);
diff --git a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcDialogFragment.java b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcDialogFragment.java
index ff28993..dd102dc 100644
--- a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcDialogFragment.java
+++ b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcDialogFragment.java
@@ -21,7 +21,6 @@
import android.support.v4.app.DialogFragment;
import com.shipdream.lib.android.mvc.event.BaseEventV2V;
-import com.shipdream.lib.poke.exception.PokeException;
/**
* This dialog fragment can either use {@link AlertDialog.Builder} to build a alert dialog or use
@@ -41,11 +40,8 @@ public void onCreate(Bundle savedInstanceState) {
setRetainInstance(true);
}
- try {
- AndroidMvc.graph().inject(this);
- } catch (PokeException e) {
- throw new RuntimeException(e);
- }
+ AndroidMvc.graph().inject(this);
+
eventRegister = new EventRegister(this);
eventRegister.registerEventBuses();
}
diff --git a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcFragment.java b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcFragment.java
index 6f7bcce..df82fd6 100644
--- a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcFragment.java
+++ b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcFragment.java
@@ -23,7 +23,6 @@
import android.view.ViewGroup;
import com.shipdream.lib.android.mvc.event.BaseEventV2V;
-import com.shipdream.lib.poke.exception.PokeException;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -108,12 +107,8 @@ protected int getCurrentOrientation() {
void injectDependencies() {
if (!dependenciesInjected) {
- try {
- AndroidMvc.graph().inject(this);
- dependenciesInjected = true;
- } catch (PokeException e) {
- throw new RuntimeException(e);
- }
+ AndroidMvc.graph().inject(this);
+ dependenciesInjected = true;
}
}
diff --git a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcService.java b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcService.java
index 6423189..2a25485 100644
--- a/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcService.java
+++ b/library/android-mvc/src/main/java/com/shipdream/lib/android/mvc/view/MvcService.java
@@ -19,7 +19,6 @@
import android.app.Service;
import com.shipdream.lib.android.mvc.event.BaseEventV2V;
-import com.shipdream.lib.poke.exception.PokeException;
/**
* Android service can be thought as a kind of view sitting on top and driven by controller which
@@ -34,11 +33,9 @@ public abstract class MvcService extends Service{
@Override
public void onCreate() {
super.onCreate();
- try {
- AndroidMvc.graph().inject(this);
- } catch (PokeException e) {
- throw new RuntimeException(e);
- }
+
+ AndroidMvc.graph().inject(this);
+
eventRegister = new EventRegister(this);
eventRegister.registerEventBuses();
}
diff --git a/library/poke/src/main/java/com/shipdream/lib/poke/Graph.java b/library/poke/src/main/java/com/shipdream/lib/poke/Graph.java
index 11cdc53..8301617 100644
--- a/library/poke/src/main/java/com/shipdream/lib/poke/Graph.java
+++ b/library/poke/src/main/java/com/shipdream/lib/poke/Graph.java
@@ -16,11 +16,11 @@
package com.shipdream.lib.poke;
+import com.shipdream.lib.poke.Provider.OnFreedListener;
import com.shipdream.lib.poke.exception.CircularDependenciesException;
import com.shipdream.lib.poke.exception.ProvideException;
import com.shipdream.lib.poke.exception.ProviderMissingException;
import com.shipdream.lib.poke.util.ReflectUtils;
-import com.shipdream.lib.poke.Provider.OnFreedListener;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
@@ -121,65 +121,73 @@ public void clearMonitors() {
}
/**
- * Inject all fields annotated by the given injectAnnotation
+ * Add {@link ProviderFinder} to the graph directly. Eg. if manual provider registration
+ * is needed, a {@link com.shipdream.lib.poke.ProviderFinderByRegistry} can be added.
+ *
+ * Note that, when there are multiple {@link ProviderFinder}s able to inject an instance the
+ * later merged graph wins.
*
- * @param target Whose fields will be injected
- * @param injectAnnotation Annotated which a field will be recognize
- * @throws ProvideException
+ * @param providerFinders The {@link ProviderFinder}s to add
*/
- public void inject(Object target, Class extends Annotation> injectAnnotation) throws ProvideException, ProviderMissingException, CircularDependenciesException {
- if (monitors != null) {
- int size = monitors.size();
- for (int i = 0; i < size; i++) {
- monitors.get(i).onInject(target);
- }
+ protected void addProviderFinders(ProviderFinder... providerFinders) {
+ if (this.providerFinders == null) {
+ this.providerFinders = new ArrayList<>();
}
- doInject(target, null, null, injectAnnotation);
- visitedInjectNodes.clear();
- revisitedNode = null;
- visitedFields.clear();
+ this.providerFinders.addAll(Arrays.asList(providerFinders));
}
/**
- * Release cached instances held by fields of target object. References of cache of the
- * instances will be decremented. Once the reference count of a controller reaches 0, it will
- * be removed from the cache and raise {@link OnFreedListener}.
+ * Inject all fields annotated by the given injectAnnotation
*
* @param target Whose fields will be injected
* @param injectAnnotation Annotated which a field will be recognize
+ * @throws ProvideException
*/
- public void release(Object target, Class extends Annotation> injectAnnotation) {
+ public void inject(Object target, Class extends Annotation> injectAnnotation)
+ throws ProvideException, ProviderMissingException, CircularDependenciesException {
if (monitors != null) {
int size = monitors.size();
for (int i = 0; i < size; i++) {
- monitors.get(i).onRelease(target);
+ monitors.get(i).onInject(target);
}
}
- doRelease(target, null, null, injectAnnotation);
+ doInject(target, null, null, injectAnnotation, true);
visitedInjectNodes.clear();
revisitedNode = null;
visitedFields.clear();
}
/**
- * Add {@link ProviderFinder} to the graph directly. Eg. if manual provider registration
- * is needed, a {@link com.shipdream.lib.poke.ProviderFinderByRegistry} can be added.
- *
- * Note that, when there are multiple {@link ProviderFinder}s able to inject an instance the
- * later merged graph wins.
+ * Get an instance matching the type and qualifier. If there is an instance cached, the cached
+ * instance will be returned otherwise a new instance will be created.
*
- * @param providerFinders The {@link ProviderFinder}s to add
+ * Note that, not like {@link #inject(Object, Class)} this method will NOT increment
+ * reference count for the injectable object with the same type and qualifier.
+ * @param type the type of the object
+ * @param qualifier the qualifier of the injected object. Null is allowed if no qualifier is specified
+ * @return The cached object or a new instance matching the type and qualifier
+ * @throws ProviderMissingException throw if the provider matching the requiredType and qualifier is not found
+ * @throws ProvideException throw when failed to create a new instance
+ * @throws CircularDependenciesException throw when circular dependency found during injecting the newly created instance
*/
- protected void addProviderFinders(ProviderFinder... providerFinders) {
- if (this.providerFinders == null) {
- this.providerFinders = new ArrayList<>();
+ public T get(Class type, Annotation qualifier, Class extends Annotation> injectAnnotation)
+ throws ProviderMissingException, ProvideException, CircularDependenciesException {
+ Provider provider = getProvider(type, qualifier);
+ T cachedInstance = provider.findCachedInstance();
+ if (cachedInstance != null) {
+ return cachedInstance;
+ } else {
+ T newInstance = provider.createInstance();
+
+ doInject(newInstance, null, null, injectAnnotation, false);
+
+ return newInstance;
}
- this.providerFinders.addAll(Arrays.asList(providerFinders));
}
@SuppressWarnings("unchecked")
private void doInject(Object target, Class targetType, Annotation targetQualifier,
- Class extends Annotation> injectAnnotation)
+ Class extends Annotation> injectAnnotation, boolean retainReference)
throws ProvideException, ProviderMissingException, CircularDependenciesException {
boolean circularDetected = false;
Provider targetProvider;
@@ -203,7 +211,7 @@ private void doInject(Object target, Class targetType, Annotation targetQualifie
}
}
- if (!circularDetected) {
+ if (!circularDetected && target != null) {
Class> clazz = target.getClass();
while (clazz != null) {
Field[] fields = clazz.getDeclaredFields();
@@ -212,22 +220,27 @@ private void doInject(Object target, Class targetType, Annotation targetQualifie
Class fieldType = field.getType();
Annotation fieldQualifier = ReflectUtils.findFirstQualifier(field);
Provider provider = getProvider(fieldType, fieldQualifier);
- if (provider != null) {
- Object impl = provider.get();
- ReflectUtils.setField(target, field, impl);
+
+ Object impl;
+ if (retainReference) {
+ impl = provider.get();
provider.retain(target, field);
- boolean firstTimeInject = provider.totalReference() == 1;
- if (!isFieldVisited(impl, field)) {
- doInject(impl, fieldType, fieldQualifier, injectAnnotation);
- }
- if (firstTimeInject) {
- provider.notifyInjected(impl);
- }
- recordVisitField(impl, field);
} else {
- throw new ProviderMissingException(String.format("Provider for %s is missing. Make " +
- "sure the provider is registered in advance.", fieldType));
+ impl = provider.createInstance();
}
+
+ ReflectUtils.setField(target, field, impl);
+
+ boolean firstTimeInject = provider.totalReference() == 1;
+ if (!isFieldVisited(impl, field)) {
+ doInject(impl, fieldType, fieldQualifier, injectAnnotation, retainReference);
+ }
+
+ if (firstTimeInject) {
+ provider.notifyInjected(impl);
+ }
+
+ recordVisitField(impl, field);
}
}
clazz = clazz.getSuperclass();
@@ -239,8 +252,29 @@ private void doInject(Object target, Class targetType, Annotation targetQualifie
}
}
+ /**
+ * Release cached instances held by fields of target object. References of cache of the
+ * instances will be decremented. Once the reference count of a controller reaches 0, it will
+ * be removed from the cache and raise {@link OnFreedListener}.
+ *
+ * @param target Whose fields will be injected
+ * @param injectAnnotation Annotated which a field will be recognize
+ */
+ public void release(Object target, Class extends Annotation> injectAnnotation) throws ProviderMissingException {
+ if (monitors != null) {
+ int size = monitors.size();
+ for (int i = 0; i < size; i++) {
+ monitors.get(i).onRelease(target);
+ }
+ }
+ doRelease(target, null, null, injectAnnotation);
+ visitedInjectNodes.clear();
+ revisitedNode = null;
+ visitedFields.clear();
+ }
+
private void doRelease(Object target, Class targetType, Annotation targetQualifier,
- final Class extends Annotation> injectAnnotation) {
+ final Class extends Annotation> injectAnnotation) throws ProviderMissingException {
Class> clazz = target.getClass();
boolean circularDetected = false;
@@ -258,14 +292,7 @@ private void doRelease(Object target, Class targetType, Annotation targetQualifi
if(fieldValue != null) {
final Class> fieldType = field.getType();
Annotation fieldQualifier = ReflectUtils.findFirstQualifier(field);
- Provider provider;
- try {
- provider = getProvider(fieldType, fieldQualifier);
- } catch (ProviderMissingException e) {
- throw new RuntimeException(String.format("Can't find provider " +
- "for %s with qualifier %s", fieldType.getName(), "@"
- + (targetQualifier == null ? "null" : targetQualifier.toString())));
- }
+ Provider provider = getProvider(fieldType, fieldQualifier);
boolean stillReferenced = provider.getReferenceCount(target, field) > 0;
if (!isFieldVisited(target, field) && stillReferenced) {
@@ -281,6 +308,7 @@ private void doRelease(Object target, Class targetType, Annotation targetQualifi
onProviderFreedListeners.get(k).onFreed(provider);
}
}
+
provider.freeCache();
}
}
@@ -348,6 +376,10 @@ Provider getProvider(Class type, Annotation qualifier) throws ProviderMissingExc
provider = providerFinder.findProvider(type, qualifier);
}
+ if (provider == null) {
+ throw new ProviderMissingException(type, qualifier);
+ }
+
return provider;
}
diff --git a/library/poke/src/main/java/com/shipdream/lib/poke/ImplClassLocator.java b/library/poke/src/main/java/com/shipdream/lib/poke/ImplClassLocator.java
index b137682..f439fc3 100644
--- a/library/poke/src/main/java/com/shipdream/lib/poke/ImplClassLocator.java
+++ b/library/poke/src/main/java/com/shipdream/lib/poke/ImplClassLocator.java
@@ -27,7 +27,7 @@ public abstract class ImplClassLocator {
* @param
* @return
*/
- public abstract Class locateImpl(Class contract) throws LocateClassException;
+ public abstract Class locateImpl(Class contract) throws ImplClassNotFoundException;
/**
* Define the {@link ScopeCache} for the injectable contract located by this
diff --git a/library/poke/src/main/java/com/shipdream/lib/poke/ImplClassLocatorByPattern.java b/library/poke/src/main/java/com/shipdream/lib/poke/ImplClassLocatorByPattern.java
index 50000bb..dc9503c 100644
--- a/library/poke/src/main/java/com/shipdream/lib/poke/ImplClassLocatorByPattern.java
+++ b/library/poke/src/main/java/com/shipdream/lib/poke/ImplClassLocatorByPattern.java
@@ -36,13 +36,13 @@ public ImplClassLocatorByPattern(ScopeCache scopeCache) {
}
@Override
- public Class locateImpl(Class contract) throws LocateClassException {
+ public Class locateImpl(Class contract) throws ImplClassNotFoundException {
String pkg = contract.getPackage().getName();
String implClassName = pkg + ".internal." + contract.getSimpleName() + "Impl";
try {
return (Class) Class.forName(implClassName);
} catch (ClassNotFoundException e) {
- throw new LocateClassException("Can't locate implementation class for " + contract.getName(), e);
+ throw new ImplClassNotFoundException("Can't find implementation class for " + contract.getName(), e);
}
}
diff --git a/library/poke/src/main/java/com/shipdream/lib/poke/LocateClassException.java b/library/poke/src/main/java/com/shipdream/lib/poke/ImplClassNotFoundException.java
similarity index 83%
rename from library/poke/src/main/java/com/shipdream/lib/poke/LocateClassException.java
rename to library/poke/src/main/java/com/shipdream/lib/poke/ImplClassNotFoundException.java
index e67d70d..459556f 100644
--- a/library/poke/src/main/java/com/shipdream/lib/poke/LocateClassException.java
+++ b/library/poke/src/main/java/com/shipdream/lib/poke/ImplClassNotFoundException.java
@@ -16,8 +16,8 @@
package com.shipdream.lib.poke;
-public class LocateClassException extends Exception {
- public LocateClassException(String message, Throwable cause) {
+public class ImplClassNotFoundException extends Exception {
+ public ImplClassNotFoundException(String message, Throwable cause) {
super(message, cause);
}
}
diff --git a/library/poke/src/main/java/com/shipdream/lib/poke/Provider.java b/library/poke/src/main/java/com/shipdream/lib/poke/Provider.java
index 41b7dde..ab19571 100644
--- a/library/poke/src/main/java/com/shipdream/lib/poke/Provider.java
+++ b/library/poke/src/main/java/com/shipdream/lib/poke/Provider.java
@@ -76,7 +76,7 @@ int getReferenceCount(Object owner, Field field) {
return 0;
}
- int retain(Object owner, Field field) {
+ void retain(Object owner, Field field) {
totalRefCount++;
Map fields = owners.get(owner);
if (fields == null) {
@@ -87,15 +87,13 @@ int retain(Object owner, Field field) {
Integer count = fields.get(field.getName());
if (count == null) {
fields.put(field.getName(), 1);
- return 1;
} else {
count++;
fields.put(field.getName(), count);
- return count;
}
}
- int release(Object owner, Field field) {
+ void release(Object owner, Field field) {
Map fields = owners.get(owner);
if(fields!= null) {
totalRefCount--;
@@ -103,16 +101,23 @@ int release(Object owner, Field field) {
Integer count = fields.get(field.getName());
if(--count > 0) {
fields.put(field.getName(), count);
- return count;
} else {
fields.remove(field.getName());
}
}
+
if(fields != null && fields.isEmpty()) {
owners.remove(owner);
}
+ }
- return 0;
+ void freeCache() {
+ if (scopeCache != null) {
+ ScopeCache.CachedItem cachedItem = scopeCache.findCacheItem(type, qualifier);
+ if (cachedItem != null) {
+ scopeCache.removeCache(cachedItem.type, cachedItem.qualifier);
+ }
+ }
}
int totalReference() {
@@ -181,15 +186,6 @@ public T findCachedInstance() {
return null;
}
- void freeCache() {
- if (scopeCache != null) {
- ScopeCache.CachedItem cachedItem = scopeCache.findCacheItem(type, qualifier);
- if (cachedItem != null) {
- scopeCache.removeCache(cachedItem.type, cachedItem.qualifier);
- }
- }
- }
-
/**
* Register listener which will be called back when the instance is injected. It will called
* until all injectable fields of the object are fully and recursively if needed injected.
@@ -220,7 +216,7 @@ public void unregisterOnInjectedListener(OnInjectedListener listener) {
* @throws CircularDependenciesException Exception thrown if nested injection has circular dependencies
* @throws ProviderMissingException Exception thrown if nested injection misses dependencies
*/
- public final T get() throws ProvideException, CircularDependenciesException, ProviderMissingException {
+ final T get() throws ProvideException {
if(scopeCache == null) {
T impl = createInstance();
if(impl == null) {
@@ -228,6 +224,7 @@ public final T get() throws ProvideException, CircularDependenciesException, Pro
throw new ProvideException(String.format("Provider (type: %s, qualifier: " +
"%s) should not provide NULL as instance", type.getName(), qualifierName));
}
+
return impl;
} else {
return scopeCache.get(this);
diff --git a/library/poke/src/main/java/com/shipdream/lib/poke/ProviderFinderByRegistry.java b/library/poke/src/main/java/com/shipdream/lib/poke/ProviderFinderByRegistry.java
index b5f24d3..87399a1 100644
--- a/library/poke/src/main/java/com/shipdream/lib/poke/ProviderFinderByRegistry.java
+++ b/library/poke/src/main/java/com/shipdream/lib/poke/ProviderFinderByRegistry.java
@@ -18,6 +18,7 @@
import com.shipdream.lib.poke.exception.ProvideException;
import com.shipdream.lib.poke.exception.ProviderConflictException;
+import com.shipdream.lib.poke.exception.ProviderMissingException;
import com.shipdream.lib.poke.util.ReflectUtils;
import java.lang.annotation.Annotation;
@@ -42,14 +43,22 @@ private static class ProviderHolder {
@SuppressWarnings("unchecked")
@Override
- public Provider findProvider(Class type, Annotation qualifier) {
+ public Provider findProvider(Class type, Annotation qualifier) throws ProviderMissingException {
ProviderHolder providerHolder = providers.get(PokeHelper.makeProviderKey(type, qualifier));
if (providerHolder != null) {
- return providerHolder.overrider == null ?
- providerHolder.original : providerHolder.overrider;
+ if (providerHolder.overrider == null) {
+ if (providerHolder.original == null) {
+ throw new ProviderMissingException(type, qualifier);
+ } else {
+ return providerHolder.original;
+ }
+ } else {
+ return providerHolder.overrider;
+ }
+ } else {
+ return null;
}
- return null;
}
/**
diff --git a/library/poke/src/main/java/com/shipdream/lib/poke/ScopeCache.java b/library/poke/src/main/java/com/shipdream/lib/poke/ScopeCache.java
index 169dd35..cb4cb33 100644
--- a/library/poke/src/main/java/com/shipdream/lib/poke/ScopeCache.java
+++ b/library/poke/src/main/java/com/shipdream/lib/poke/ScopeCache.java
@@ -16,9 +16,7 @@
package com.shipdream.lib.poke;
-import com.shipdream.lib.poke.exception.CircularDependenciesException;
import com.shipdream.lib.poke.exception.ProvideException;
-import com.shipdream.lib.poke.exception.ProviderMissingException;
import java.lang.annotation.Annotation;
import java.util.HashMap;
@@ -38,8 +36,7 @@ public static class CachedItem {
protected Map cache = new HashMap<>();
@SuppressWarnings("unchecked")
- T get(Provider provider) throws ProvideException, ProviderMissingException,
- CircularDependenciesException {
+ T get(Provider provider) throws ProvideException {
String key = PokeHelper.makeProviderKey(provider.type(), provider.getQualifier());
CachedItem item = cache.get(key);
if (item == null) {
diff --git a/library/poke/src/main/java/com/shipdream/lib/poke/exception/ProviderMissingException.java b/library/poke/src/main/java/com/shipdream/lib/poke/exception/ProviderMissingException.java
index b3ac1fd..a98daa9 100644
--- a/library/poke/src/main/java/com/shipdream/lib/poke/exception/ProviderMissingException.java
+++ b/library/poke/src/main/java/com/shipdream/lib/poke/exception/ProviderMissingException.java
@@ -18,15 +18,27 @@
import com.shipdream.lib.poke.Graph;
+import java.lang.annotation.Annotation;
+
/**
* Exception occurs when a {@link Graph} fails to find a provider by given injection type
*/
public class ProviderMissingException extends PokeException{
- public ProviderMissingException(String message) {
- super(message);
+ public ProviderMissingException(Class instanceType, Annotation qualifier) {
+ super(makeMessage(instanceType, qualifier));
+ }
+
+ public ProviderMissingException(Class instanceType, Annotation qualifier, Throwable cause) {
+ super(makeMessage(instanceType, qualifier), cause);
}
- public ProviderMissingException(String message, Throwable cause) {
- super(message, cause);
+ private static String makeMessage(Class instanceType, Annotation qualifier) {
+ if (qualifier == null) {
+ return String.format("Provider for type: %s cannot be found. Please if it's defined properly.", instanceType.getName());
+ } else {
+ return String.format("Provider for type: %s, qualifier: %s cannot be found. Please if it's defined properly.",
+ instanceType.getName(), qualifier.toString());
+ }
+
}
}
diff --git a/library/poke/src/test/java/com/shipdream/lib/poke/TestInjectionReferenceCount.java b/library/poke/src/test/java/com/shipdream/lib/poke/TestInjectionReferenceCount.java
index c7ec3ee..2f857cd 100644
--- a/library/poke/src/test/java/com/shipdream/lib/poke/TestInjectionReferenceCount.java
+++ b/library/poke/src/test/java/com/shipdream/lib/poke/TestInjectionReferenceCount.java
@@ -96,6 +96,41 @@ public Container providesContainer() {
}
}
+ @Test
+ public void should_be_able_to_get_cached_instance() throws ProvideException, ProviderConflictException,
+ CircularDependenciesException, ProviderMissingException {
+ SimpleGraph graph = new SimpleGraph();
+ Component component = new TestComp2();
+ graph.register(component);
+
+ Container container = graph.get(Container.class, null, MyInject.class);
+ Assert.assertNotNull(((Fridge) container).a);
+ Assert.assertNotNull(((Fridge) container).b);
+
+ Assert.assertTrue(component.getScopeCache().cache.isEmpty());
+
+ House house = new House();
+ graph.inject(house, MyInject.class);
+
+ Assert.assertNotNull(house.container);
+ Assert.assertNotNull(((Fridge) house.container).a);
+ Assert.assertNotNull(((Fridge) house.container).b);
+ Assert.assertTrue(((Fridge) house.container).a == ((Fridge) house.container).b);
+
+ Assert.assertTrue(((Fridge) container).a != house.container);
+ Assert.assertTrue(((Fridge) container).a != ((Fridge) house.container).a);
+ Assert.assertTrue(((Fridge) container).b != ((Fridge) house.container).b);
+
+ Provider containerProvider = graph.getProvider(Container.class, null);
+ Provider fruitProvider = graph.getProvider(Fruit.class, null);
+
+ Assert.assertTrue(containerProvider.totalReference() == 1);
+ Assert.assertTrue(fruitProvider.totalReference() == 2);
+
+ graph.release(house, MyInject.class);
+ Assert.assertTrue(component.getScopeCache().cache.isEmpty());
+ }
+
@Test
public void referenceCountCanReduceCascadinglyFromRoot() throws ProvideException, ProviderConflictException,
CircularDependenciesException, ProviderMissingException {
@@ -190,8 +225,6 @@ public void releaseInjectedFieldsShouldSetThemNull() throws ProvideException, Pr
Assert.assertEquals(2, fruitProvider.totalReference());
graph.release(kitchen.container, MyInject.class);
-// Assert.assertNull(((Fridge) kitchen.container).a);
-// Assert.assertNull(((Fridge) kitchen.container).b);
Assert.assertNotNull(kitchen.aOnFloor);
Assert.assertNotNull(kitchen.bOnFloor);
@@ -200,8 +233,6 @@ public void releaseInjectedFieldsShouldSetThemNull() throws ProvideException, Pr
Assert.assertTrue(fruitProvider.totalReference() == 2);
graph.release(kitchen, MyInject.class);
-// Assert.assertNull(kitchen.aOnFloor);
-// Assert.assertNull(kitchen.bOnFloor);
Assert.assertTrue(component.getScopeCache().cache.isEmpty());
}
diff --git a/samples/benchmark/src/main/java/com/shipdream/lib/android/mvc/samples/benchmark/MainActivity.java b/samples/benchmark/src/main/java/com/shipdream/lib/android/mvc/samples/benchmark/MainActivity.java
index ad4d614..8531472 100644
--- a/samples/benchmark/src/main/java/com/shipdream/lib/android/mvc/samples/benchmark/MainActivity.java
+++ b/samples/benchmark/src/main/java/com/shipdream/lib/android/mvc/samples/benchmark/MainActivity.java
@@ -65,7 +65,7 @@
import com.shipdream.lib.poke.Graph;
import com.shipdream.lib.poke.ImplClassLocator;
import com.shipdream.lib.poke.ImplClassLocatorByPattern;
-import com.shipdream.lib.poke.LocateClassException;
+import com.shipdream.lib.poke.ImplClassNotFoundException;
import com.shipdream.lib.poke.Provider;
import com.shipdream.lib.poke.ProviderByClassType;
import com.shipdream.lib.poke.ProviderFinder;
@@ -217,8 +217,8 @@ public Provider findProvider(Class type, Annotation qualifier) throws
try {
Class impl = implClassLocatorByPattern.locateImpl(type);
return new ProviderByClassType(type, impl);
- } catch (LocateClassException e) {
- throw new RuntimeException(e);
+ } catch (ImplClassNotFoundException e) {
+ throw new ProviderMissingException(type, qualifier, e);
}
}
});
@@ -252,8 +252,8 @@ public Provider findProvider(Class type, Annotation qualifier) throws
try {
Class impl = implClassLocatorByPattern.locateImpl(type);
return new ProviderByClassType(type, impl);
- } catch (LocateClassException e) {
- throw new RuntimeException(e);
+ } catch (ImplClassNotFoundException e) {
+ throw new ProviderMissingException(type, qualifier, e);
}
}
});