Is it possible that one class access the method from another class by using the interface reference??
Suppose, i have a class that is loginUIController.java, from this class i want to access method of another class that is mainController.java. But I won't access the method directly. for accessing method from mainController.java i'll use the Interface of mainController.java which is InferfaceMainController.java.
The following classes are :-
Here is the loginUIController.java
public class LoginUIController
{
InterfaceMainController mainController = null;
private void handleButtonAction(ActionEvent event) throws IOException
{
String userid = txt_username.getText();
String password = txt_password.getText();
mainController.checkLogin(userid, password);
}
}
InterfaceMainController :-
public interface InterfaceMainController {
void checkLogin(String userid, String password);
void addContact(String name, String phone, String address, String email);
}
mainController :-
public class MainController implements InterfaceMainController{
#Override
public void checkLogin(String userid, String password){
Users u = new Users();
u.setUserid(userid);
u.setPassword(password);
DBLayer db1 = new DBLayer();
try
{
if(db1.userExists(u))
{
System.out.println("login Success.");
}
else
{
System.out.println("login Failed.");
}
} catch (Exception ex) {
e.printStackTrace();
}
}
}
Now, how to access checkLogin(String userid, String password);of mainController.java from the loginUIController.java by creating the interface object of InterfaceMainController.java?
From the point of view of LoginUIController, there's no such thing as MainController. LoginUIController only knows about InterfaceMainController. That's essentially what you defined in:
InterfaceMainController mainController = null;
To work with an instance of InterfaceMainController you first need an implementation of the interface, which in your case is MainController. Then, you create an instance of the implementation:
InterfaceMainController mainController = new MainController();
Finally, you need to provide the instance to whatever needs it, in your case LoginUIController. A common way to do this is to create a constructor like so:
public class LoginUIController
{
InterfaceMainController mainController = null;
public LoginUIController(InterfaceMainController mainController) {
this.mainController = mainController
}
...
}
The above is an example of the dependency injection Elliot referenced.
There's not really a difference in how you do it. It's really the handle you have.
InterfaceMainController foo = new MainController();
foo.checkLogin("me", "my password");
You can pass foo to any method that expects an InterfaceMainController. But the code otherwise looks the same. It's only the variable type that changes.
From the code snippets, it appears you are missing one object which implements the interface InterfaceMainController (in your example this would be an instance of MainController). I can think of two options to remedy this:
Pass the object to the constructor of LoginUIController.
Use Inversion of Control (IOC) / Dependency Injection.
Option #1 is ok so far as it goes, but in such an approach you would be responsible for object lifecycle and ownership. Option #2 is not a Java language feature, but rather something provided by Frameworks, eg Spring.
Yes it is possible to pass MainController obj to InterfaceMainController reference variable.
Without Spring
InterfaceMainController mainController = new MainController();
Using Spring annotation
If you are using spring then you can use annotations to auto wire the MainController object with #component and #Autowired something like this
#Component
public class MainController implements InterfaceMainController {
........
}
and auto wire mainController with annotation #Autowired like this
#Autowired
InterfaceMainController mainController
Related
I'm quite new to spring (switching from PHP to Java).
In my code I have a java.lang.reflect.Method objects and I need to instantiate it's class with all it's dependencies.
Normally I'd use #Autowired annotation in my code, but it's not possible because my code gets different Method objects, not specific classes.
Question is - how to get a class instance from dependency container without using annotations and having just class name?
In php i used libraries which gave me access to container and I could just get DI services by it's class name just like:
$this->container->get('My\Class\Name');
In spring I tried:
#Autowired
private ApplicationContext context;
void myMethod(Method method){
this.context.getBean(method.getClass());
and
this.context.getBean(method.getClass().getName());
and that was resulting in NullPointerException.
EDIT
Thanks for quick replys,
I tried using
context.getBean(method.getDeclaringClass());
and
context.getBean(method.getDeclaringClass().getSimpleName());
And it both resulted in NullPointerException as well.
Actually it's okay for my needs to get that class by class or by name. I'm trying to write my own command bus for CQRS.
Let me show you some code:
Handler:
public class SimpleCommandBus implements CommandBus {
#Autowired
private ApplicationContext context;
private Map<Class, Method> registry = new HashMap<>();
#Override
public void register(Class c, Method o) {
registry.put(c, o);
}
#Override
public void dispatch(Object command) {
if (!registry.containsKey(command.getClass())) {
throw new CommandDispatchException(String.format("Handler for command %s was not defined.", command));
}
Method method = registry.get(command.getClass());
Object handler = context.getBean(method.getDeclaringClass().getSimpleName());//line causing exception
Service class:
#Service
public class TestHandler {
public void handle(TestCommand command){
System.err.println(command.getId());
}
}
Calling command bus:
Method method = TestHandler.class.getMethod("handle", TestCommand.class);
TestCommand command = new TestCommand("Test command");
commandBus.register(TestCommand.class, method);
commandBus.dispatch(command);
Use java.lang.reflect.Method.getDeclaringClass() to find in which class the given method is declared. method.getClass() will return the type of method object which is java.lang.reflect.Method.
#Autowired
AplicationContext ctx;
...
Object bean = ctx.getBean(method.getDeclaringClass());
In Spring the default name is the simple name.
Plus as in Karols answer you must use getDeclaringClass() to get the class of the class with the method.
So you must call
this.context.getBean(method.getDeclaringClass().getSimpleName());
I want to set some non-UI fields in the controller before the initialize method of the controller gets called automatically upon creation. As I understand it, the way to do it is to provide custom ControllerFactory, since initialize() gets called after ControllerFactory returns the created object. I wanted to use the following code as per this answer:
FXMLLoader loader = new FXMLLoader(mainFXML); // some .fxml file to load
loader.setControllerFactory(param -> {
Object controller = null;
try {
controller = ReflectUtil.newInstance(param); // this is default behaviour
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
if (controller instanceof Swappable) {
((Swappable) controller).setSwapper(swapper); // this is what I want to add
}
return controller;
});
However, the ReflectUtil class (which is used in default setControllerFactory method) is part of com.sun.reflect.misc package, which I am not able to use, since compiling fails with error: package sun.reflect.misc does not exist.
As I understand it, I can't use sun packages, since this is not public API. So the question is: what do I do? I can't find any other examples of this, only the ones with ReflectUtil and, well, I want my ControllerFactory to comply with default workflow of JavaFX with #FXML annotations and all that, is this possible with some other DI framework like Jodd Petite, for example? Is there some other way to set the field? (other than to synchronize on it and wait in initialize() until the setter method gets called from other thread).
Full code on github for context.
If you want to create an instance via reflection then you need to use Class.getConstructor(Class...)1 followed by Constructor.newInstance(Object...).
FXMLLoader loader = new FXMLLoader(/* some location */);
loader.setControllerFactory(param -> {
Object controller;
try {
controller = param.getConstructor().newInstance();
} catch (ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
if (controller instanceof Swappable) {
((Swappable) controller).setSwapper(swapper);
}
return controller;
}
This code requires that your controller class has a public, no-argument constructor. If you want to inject your dependencies through the constructor you could do something like:
FXMLLoader loader = new FXMLLoader(/* some location */);
loader.setControllerFactory(param -> {
Object controller;
try {
if (Swappable.class.isAssignableFrom(param)) {
controller = param.getConstructor(Swapper.class).newInstance(swapper);
} else {
controller = param.getConstructor().newInstance();
}
} catch (ReflectiveOperationException ex) {
throw new RuntimeException(ex);
}
return controller;
}
This code assumes that all subclasses of Swappable have a public, single-argument constructor that takes a Swapper.
If you want to get a non-public constructor you'll need to use Constructor.getDeclaredConstructor(Class...). Then you'd need to call setAccessible(true) on the Constructor before invoking it.
Couple things to remember if using Jigsaw modules (Java 9+) and this controller factory code is not in the same module as the controller class. Let's say the controller factory code is in module foo and the controller class is in module bar:
If using a public controller with a public constructor then bar must exports the controller class' package to at least foo
If using a non-public controller and/or constructor then the same thing must happen but with opens instead of exports
Otherwise an exception will be thrown.
1. If using a no-argument (not necessarily public) constructor you can bypass getConstructor and call Class.newInstance() directly. However, please note that this method has issues and has be deprecated since Java 9.
Personally, using reflection for my own code is a sign of bad design.
Here's a suggestion that uses FXML mechanisms to inject a user instance of an object. For this purpose, an object is created that describes the context in which the application works. Object user entities are registered in this object. This imposes some constraint on users not to implement a direct interface but to inherit an abstract class that will implement the logic of registering the instance in the context.
public interface Swapper {
}
public abstract class AbstractSwapper implements Swapper {
public AbstractSwapper() {
ApplicationContext.getInstance().setSwapper(this);
}
}
public class ApplicationContext {
private static ApplicationContext instance;
private Swapper swapper;
private ApplicationContext() {
}
public synchronized static ApplicationContext getInstance() {
if(instance == null) {
instance = new ApplicationContext();
}
return instance;
}
public synchronized static Swapper swapperFactory() {
Swapper swapper = getInstance().getSwapper();
if(swapper == null) {
swapper = new AbstractSwapper() {
};
getInstance().setSwapper(swapper);
}
return swapper;
}
public Swapper getSwapper() {
return swapper;
}
public void setSwapper(Swapper swapper) {
this.swapper = swapper;
}
}
In this case, the FXML file can be used fx:factory to use the swapper instance registered in ApplicationContext. Thus, FXMLLoader will inject the instance directly into the controller.
<GridPane fx:controller="sample.Controller" xmlns:fx="http://javafx.com/fxml" >
<fx:define>
<ApplicationContext fx:factory="swapperFactory" fx:id="swapper"/>
</fx:define>
</GridPane>
and sample.Controller
public class Controller {
#FXML
private Swapper swapper;
}
Another solution is for the controller to initialize the fields using the ApplicationContext directly. So the swapper field does not bind to the FXML file.
public class Controller {
private Swapper swapper;
#FXML
private void initialize() {
swapper = ApplicationContext.swapperFactory();
}
}
In both versions, the user simply has to create an instance of AbstractSwapper before using FXMLLoader.
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception{
AbstractSwapper s = new AbstractSwapper() {
};
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Also, there is an option to use FXMLLoader to inject the object. In this case it goes through fx:reference or through fx:copy (if you have copy constructor)
I´m using Guice to initalize a class with some arguments from a config file
#Provides
#Singleton
RetryServiceCaller provideMaxRetryAttempts(#Named("config") JsonObject config) throws IOException {
JsonObject retryDetails = config.getJsonObject("retry_details");
return new RetryServiceCaller(retryDetails.getInteger("maxRetryAttempts"), retryDetails.getInteger("upperBoundary"), retryDetails.getInteger("lowerBoundary"),
retryDetails.getLong("multiplicationFactor"), retryDetails.getInteger("timeout"), retryDetails.getInteger("increaseTimeout"));
}
This class is injected in another class which is singleton as well.
class A{
#Inject private RetryServiceCaller retryServiceCaller;
}
But now the problem is that since this new class A is singleton, I need to clone the retryServiceCaller every time that somebody use this class A.
I´ve been investigating FactoryModuleBuilder to use it and create a factory for this class. But since the class has parameters from the config file I could not find the way to make it works.
Something like this
class A{
#Inject private RetryServiceCaller.Factory retryServiceCallerFactory;
}
Then in my RetryServiceCaller implement this
public interface Factory {
#Inject
RetryServiceCaller create();
}
#Inject
public RetryServiceCaller(int maxRetryAttempts, int upperBoundary, int lowerBoundary, long multiplicationFactor, int timeout, int incrementTimeout) {
this.maxRetryAttempts = maxRetryAttempts;
this.upperBoundary = upperBoundary;
this.lowerBoundary = lowerBoundary;
this.multiplicationFactor = multiplicationFactor;
this.timeout = timeout;
this.incrementTimeout = incrementTimeout;
}
But guice throw me errors saying
No implementation for com.proxy.handlers.RetryServiceCaller$Factory was bound
Guice can automatically provide a zero-argument factory: Instead of injecting Foo, you can always inject Provider<Foo>. This allows you to call fooProvider.get() to create an instance whenever and wherever you'd like. You don't have to bind to a Provider or use a Provides method to get access to this; you can inject Foo or Provider<Foo> whether you use a bind(...).to(...) type binding, a toProvider binding, a toInstance binding, a #Provides method, or anything else, and Guice will call get or return an internal Provider automatically.
(The returned Provider will also respect scopes, so you'll need to drop your #Singleton scope in order to get more than one instance, and be aware that toInstance bindings will always return the same instance.)
This is not a job for FactoryModuleBuilder; only use FactoryModuleBuilder when you need to mix injected and non-injected constructor parameters in the same type.
Your finished binding should look like this:
#Provides
/* NOT #Singleton */
RetryServiceCaller provideMaxRetryAttempts(#Named("config") JsonObject config) throws IOException {
JsonObject retryDetails = config.getJsonObject("retry_details");
return new RetryServiceCaller(retryDetails.getInteger("maxRetryAttempts"), retryDetails.getInteger("upperBoundary"), retryDetails.getInteger("lowerBoundary"),
retryDetails.getLong("multiplicationFactor"), retryDetails.getInteger("timeout"), retryDetails.getInteger("increaseTimeout"));
}
And in your class:
#Inject public YourCallerConsumer(Provider<RetryServiceCaller> callerProvider) {
this.callerProvider = callerProvider;
}
public void doAction() {
RetryServiceCaller newCaller = callerProvider.get();
// interact with caller
}
Your first approach should work just fine. If you don't want the RetryServiceCaller to be a singleton, remove the #Singleton annotation from the provider method, and a new instance will be created for every injection point.
Assisted inject could work here too, but it's overkill. If you want to go that route:
interface RetryServiceCallerFactory {
RetryServiceCaller create(String configParam1, String configParam2);
}
public class RetryServiceCaller {
#AssistedInject
public RetryServiceCaller(String configParam1, String configParam2) {}
}
then, in your module
install(new FactoryModuleBuilder().build(Factory.class);
and in your injection points
#Inject RetryServiceCallerFactory factory;
RetryServiceCaller create(JsonObject config) {
return factory.create(config.getFirstParam(), config.getSecondParam());
}
You can refer to the documentation for more extensive examples.
I am using Play 2.4. I have a controller which extends play.mvc.Controller. There I am setting user object in session as below:
session("username", user);
Now I want to read this session object in my service class which doesn't extend play.mvc.Controller, am not getting how I can read this, so please assist.
It is possible by using the Http.Context class:
import play.mvc.Http;
class Service {
public void something() {
String username = Http.Context.current().session().get("username");
// do something
}
}
But, should you? It is very unusual that a layer that is below (service) know things about the layer above (controllers). The code above is harder to test, per instance. Why not rewrite it so that your service receives what it needs from the above layer?
class Service {
public void something(String username) {
// do something
}
}
And your controller will do:
class MyController extends Controller {
public Result action() {
String username = session("username");
service.something(username);
}
}
I have the following scenario:
public interface ServiceClientAdapter {
SomeData getSomeData()
}
#LegacyServiceClientAdapter
public class MyLegacyServiceClientAdapterImpl implements ServiceClientAdapter {
public SomeData getSomeData() {
// implementation
}
}
#NewServiceClientAdapter
public class MyNewServiceClientAdapterImpl implements ServiceClientAdapter {
public SomeData getSomeData() {
// implementation
}
}
public class BusinessLogic {
#Inject
private ServiceClientAdapter serviceClientAdapter;
}
LegacyServiceClientAdapter and NewServiceClientAdapter are custom annotations.
The implementation for the serviceClientAdapter field will be determined at runtime by whether the user has been migrated from the legacy to the new service or not.
What is the best way to accomplish this dependency injection using Google Guice?
Take into account that different BusinessLogic classes will exist, each with their own (different) ServiceClientAdapter-like interface and corresponding legacy and new implementation classes.
Ideally this should be done with a piece of framework code that can be used across all use cases.
I'm going to assume that the result of your LDAP call can be represented as a string, let's say "legacy" or "new". If not, hopefully you should still be able to adapt this example.
In your module, use a MapBinder:
public class BusinessLogicModule {
#Override
protected void configure() {
// create empty map binder
MapBinder<String, ServiceClientAdapter> mapBinder =
MapBinder.newMapBinder(
binder(), String.class, ServiceClientAdapter.class);
// bind different impls, keyed by descriptive strings
mapBinder.addBinding("legacy")
.to(MyLegacyServiceClientAdapterImpl.class);
mapBinder.addBinding("new")
.to(MyNewServiceClientAdapterImpl.class);
}
}
Now you can inject a map of instances (or a map of providers of instances if you need to keep creating new instances) into your main class and use the string discovered at runtime to control which kind of instance you get.
public class BusinessLogic {
#Inject
private ServiceClientAdapter serviceClientAdapter;
#Inject
private Map<String, ServiceClientAdapter> mapBinder;
public void setupAndUseClientAdapter() {
String userType = getUserTypeFromLdapServer();
serviceClientAdapter = mapBinder.get(userType);
if (serviceClientAdapter == null) {
throw new IllegalArgumentException(
"No service client adapter available for " +
userType + " user type.";
}
doStuffWithServiceClientAdapter();
}
}