I have this code that initializes Calligraphy default configuration.
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
// The initialization I want to move
CalligraphyConfig.initDefault(new CalligraphyConfig.Builder()
.setDefaultFontPath("fonts/MyFont.ttf")
.build()
);
}
}
I want to use Dagger 2 in my project but I don't fully understand what classes should I create and where to move this code in order to keep the project clean ?
In short, you probably wouldn't move anything. The problem with this library is that it uses static methods for initialization and utilization. Static methods are a pain when trying to do dependency injection.
The Library (or why you would not change anything)
It looks like this library is 'just' about switching the used fonts by wrapping the context. As such it does not really provide business logic to your project, but just adds to your views / UI.
Injecting a dependency rather than just calling static methods is most useful if you either want to be able to unit test (inject mocks) or easily swap modules / behavior. In the case of globally changing fonts, both seems less likely.
If on the other hand you really need (or want to) be able to test it, or just have a clean design...
...wrap it
Static methods are a pain, because you can not have objects holding the logic. Unless you wrap them. To properly do DI with static methods, you would have to define your own interface.
public interface CalligraphyManager {
/**
* Called on app start up to initialize
*/
void init();
// other methods, like wrapping context for activity
Context wrap(Context context);
}
You now have some manager to access the static methods. The implementation should be fairly simple, since you want to do proper DI the application context and path needed for init() would be passed into the constructor of your implementation. The creation of your manager can thus be handled by your ApplicationModule—just add some provides method
#Singleton
#Provides
// You would also have to provide the path from somewhere or hardcode it
// left as an exercise for the reader
CalligraphyManager provideCalligraphyManager(Context context, String path) {
return new ActualCalligraphyManager(context, path);
}
Your application would then look something like this:
public class MyApplication extends Application {
#Inject
CalligraphyManager mCalligraphy;
#Override
public void onCreate() {
super.onCreate();
mComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
mComponent.inject(this);
// call the initialization
mCalligraphy.init();
}
}
Everything else is as usual. You have a singleton object in your application components graph, you can thus inject the same object into your activities and call `wrap´ where appropriate.
What about testing / mocking?
Since the whole reason of doing this is to make it 'testable', you can now easily provide a mock / stub object.
Create another implementation of the manager where init() would just do nothing, and wrap(Context) would just return the same context—a simple stub object.
Related
I have a huge Part source code I have to touch at 1 place. It is violating a lot of principles so I would like to extract at least the function I had to modify which is a #UIEventTopic handler. There are no tests and I would like to add them here so I know I do not break existing functionality.
I would like to move away from this:
public class MyPart {
...
#Inject
#Optional
public void event(#UIEventTopic(EVENT) EventParam p) {
...
}
}
To something like this:
public class MyPart {
...
}
public class MyEventHandler {
#Inject
#Optional
public void event(#UIEventTopic(EVENT) EventParam p, MyPart part) {
...
}
}
With the Eclipse DI I see no easy way of creating an instance of the handler class. It cannot be a #Singleton because it is a Part which can have multiple instances, and adding the handler to the IEclipseContext in the #PostConstruct is ugly because it adds a circular dependency between the part and the handler. Is there a magic how I can enforce the instantiation through the e4xmi files, or some alternative way?
My current solution is to extract purely the functionality to a utility bean and return the data and set it on the part, but this is also something not too nice (requires a lot of additional null-checks, ifs, etc.).
I am not entirely sure that I understand your question, however, this is how I would proceed:
Extract Delegate
Move the code in event() to the MyEventHandler so that MyClass fully delegates the event handling
public class MyPart {
#Inject
#Optional
public void event( #UIEventTopic(EVENT) EventParam param ) {
new MyEventHandler().handleEvent( this, param );
}
}
class MyEventHandler {
void handleEvent(MyPart part, EventParam param) {
// all code from event() goes here
}
}
This should be a safe-enough refactoring to do without having tests - and in the end, you don't have a choice as there are no tests.
Ensure the Status Quo
Now I would write tests for handleEvent(), mocking the required methods of MyPart and thus make sure that I won't break existing behavior.
Implement new Feature
After that I would be able to make the desired changes to MyEventHandler::handleEvent in a test driven manner.
Clean Up
Then I would extract an interface from MyPart that has only those methods required for MyEventHandler to do its work. If said interface gets too big, it would indicate that there is more refactoring left to do.
This question already has answers here:
What is a callback method in Java? (Term seems to be used loosely)
(6 answers)
Closed 8 years ago.
I am reading the spring documentation. All the time I get this word "callback".
For example:
Lifecycle callbacks
Initialization callbacks etc.
How do we understand callback function ? And when you say "Lifecycle callbacks" in the spring, what does it mean ?
I have kept efforts in understanding this but I am not sure if I have understood correctly.
Please help.
LifeCycle
In the context of Spring beans (which I believe is the context of what you are reading - hard to tell with the little info you've provided), beans go through different lifecycle phases (like creation and destruction). Here are the lifecycle phases of the Spring bean you can hook into:
Callback
#R.T.'s wikipedia link to what a callback is, is a good starting point to understanding callbacks. In Java, the concept of callback is implemented differently.
In object-oriented programming languages without function-valued arguments, such as in Java before its 1.7 version, callbacks can be simulated by passing an instance of an abstract class or interface, of which the receiver will call one or more methods, while the calling end provides a concrete implementation.
A good example is given by #SotiriosDelamanolis in this answer, which I'll post here just for context.
/**
* #author #SotiriosDelamanolis
* see https://stackoverflow.com/a/19405498/2587435
*/
public class Test {
public static void main(String[] args) throws Exception {
new Test().doWork(new Callback() { // implementing class
#Override
public void call() {
System.out.println("callback called");
}
});
}
public void doWork(Callback callback) {
System.out.println("doing work");
callback.call();
}
public interface Callback {
void call();
}
}
LifeCycle Callback
By looking at the image above, you can see that Spring allows you to hook into the bean lifecyle with some interfaces and annotations. For example
Hooking into the bean creation part of the lifecycle, you can implements InitializingBean, which has a callback method afterPropertiesSet(). When you implements this interface, Spring pick up on it, and calls the afterPropertiesSet().
For example
public class SomeBean implements InitializingBean {
#Override
public void afterPropertiesSet() { // this is the callback method
// for the bean creation phase of the
// spring bean lifecycle
// do something after the properties are set during bean creation
}
}
Alternatively, you can use the #PostConstruct method for a non-InitializingBean implemented method, or using the init-method in xml config.
The diagram shows other lifecycle phases you can hook into and provide "callback" method for. The lifecycle phases are underlined at the top in the diagram
You can see more at Spring reference - Lifecycle Callbacks
The wiki has a good explanation:
In computer programming, a callback is a reference to executable code,
or a piece of executable code, that is passed as an argument to other
code. This allows a lower-level software layer to call a subroutine
(or function) defined in a higher-level layer.
Also check this interesting article Java Tip 10: Implement callback routines in Java
A sample example:
interface CallBack {
void methodToCallBack();
}
class CallBackImpl implements CallBack {
public void methodToCallBack() {
System.out.println("I've been called back");
}
}
class Caller {
public void register(CallBack callback) {
callback.methodToCallBack();
}
public static void main(String[] args) {
Caller caller = new Caller();
CallBack callBack = new CallBackImpl();
caller.register(callBack);
}
}
Paul Jakubik, Callback Implementations in C++.
Callbacks are most easily described in terms of the telephone system.
A function call is analogous to calling someone on a telephone, asking
her a question, getting an answer, and hanging up; adding a callback
changes the analogy so that after asking her a question, you also give
her your name and number so she can call you back with the answer.
I am trying to build my first android app. I have multiple Activities and I am using a Handler and an AssetFileDescriptor in order to play a sound file.
My problem is, how can I pass these objects around? I have one Activity that starts a timer via the handler, and another which stops the timer via the handler. Should I pass these objects around between Activities, or is there another way?
I am not used to Java, but I was wondering if I could make a config static class or something that creates all of these objects, and then each one of my Activities would just access these objects from this static config class. However, this has its own problems, since in order to call the method getAssets(), I cannot use a static class ("Cannot make a static reference to a non-static method.")
Any ideas?
This simplest solution would be to store objects in the Application class, here is a SO answer on the topic Using the Android Application class to persist data
Another more advanced option would be to use Dagger. It is a Dependency Injection framework that can do a lot of cool stuff but is somewhat difficult to get running (atleast took me some time to get working).
Dagger enables defining a Singleton class like this:
#Singleton
public class MySingletonObject {
#Inject
MySingletonObject() {
...
}
}
And whenever you need it in your app:
public class SomeActivityOrFragment {
#Inject MySingletonObject mySingletonObject;
...
mySingletonObject.start();
}
public class SomeOtherActivityOrFragment {
#Inject MySingletonObject mySingletonObject;
...
mySingletonObject.stop();
}
public class Something {
private static Something something = new Something();
public static Something get(){
return something;
}
private EventQueueWindow eventQueue;
private Something(){
TopComponent tc = WindowManager.getDefault().findTopComponent("EventQueueWindow");
eventQueue = (EventQueueWindow) tc;
}
EventQueue getQueue(){
return eventQueue;
}
}//end class Something
Now I want to write a JUnit test which requires the ability to access eventQueue.
public void testgetQueue() {
Something something = Something.get();
assertEquals("Failed to return EventQueueWindow",something.getQueue().getClass(), EventQueueWindow.class);
}
I get a java.lang.NullPointerException when I run the test because eventQueue has a null value despite it being assigned a value in class Something's constructor. I've read around that this may have something to do with components being handle in a different thread or not being initialized before the test is run. But I'm pretty new to java and unit testing and don't know how to solve this problem. Any guidance would be appreciated.
Your biggest problem is that you have global state. Global state is generally poor programming, including with tests.
Testing for particular implementation class, probably isn't a very good test.
I suggest removing your global state and dependency upon the global state that you are lumbered with from your libraries, then test that.
I believe what is going on is that the class is designed to exist inside a large context. WindowManager gives the class access to that context but the context does not exist in the unit test therefore the manager returns null.
One solution is to have two overloads of the constructor with one taking the WindowManger as an argument. Then in the test pass a mocked WindowManager to this constructor.
Mocking example via Mockito:
WindowManager man = Mockito.mock(WindowManager.class);
EventQueueWindow window = Mockito.mock(EventQueueWindow.class);
Mockito.when(man.findTopComponent("EventQueueWindow")).thenReturn(window);
I'm managing the History in my project via Places.
What I do is this:
implement PlaceRequestHandler on top level (for example AppController),
register it -> eventBus.addHandler(PlaceRequestEvent.getType(), this);
implement method "onPlaceRequest" ,where i do project navigation.
I'm using GWT presenter and every presenter in my project overrides the onPlaceRequest method.
Why do I need this, when every request is handled from the top level "onPlaceRequest" method?
I will give an example:
public class AppController implements Presenter, PlaceRequestHandler
...........
public void bind()
{
eventBus.addHandler(PlaceRequestEvent.getType(), this);
...
}
public void onPlaceRequest(PlaceRequestEvent event)
{
// here is the project navigation tree
}
and let's take one presenter
public class SomePresenter extends Presenter<SomePresenter.Display>
{
... here some methods are overriden and
#Override
protected void onPlaceRequest(PlaceRequest request)
{
// what should I do here?
}
}
What is the idea, and how I'm supposed to use it?
Instead of making all of your presenters extend PlaceRequestHandler and managing those events yourself, you can attach a PlaceHistoryHandler and a PlaceController to your event bus. Together, they manage the browser's history and your places for you. When you ask your PlaceController to goTo() a different place, it will stop your current activity and use a mapping of places to activities (your presenters) to choose which one to start next.
To use this technique, you need to have your presenters extend AbstractActivity. Try following through Google's tutorial about it in GWT's documentation called GWT Development with Activities and Places.