How to set ControllerFactory for custom Nodes in JavaFX? - java

I have a general layout with some custom nodes, each with its own Controller. As I want to inject the same object into every of these Controllers, in order to share data between them, I create a custom ControllerFactory.
To set the ControllerFactory for the root node, I have the following working code in the start method of the Main (extends Application) class:
FXMLLoader loader = new FXMLLoader(getClass().getResource("layout.fxml"));
Main self = this;
loader.setControllerFactory((Class<?> param) -> {
return self.instantiateController(param);
});
The instantiateController method in turn just creates a new of the passed class for the moment, and logs what kind of Class was instantiated:
public Object instantiateController(Class<?> c) {
Object o = null;
try {
o = c.newInstance();
} catch (InstantiationException | IllegalAccessException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
throw new RuntimeException(ex);
}
System.out.println(o.getClass() + " instantiated");
return o;
}
This way, I can observed which Controllers were instantiated. It is always just the Controller of the root element, never of one of the custom nodes. Even though they get instatiated and are displayed as wanted, they never get factored by my factory. This way, I can not inject the object I want. How can I make the factory to be applied on all nested Controllers?

Related

Unable to use #spring annotations when class object is new

Actually i am having a spring main class as follows.
ClassLoader loader = null;
try {
loader = URLClassLoader.newInstance(new URL[]{new
File(plugins + "/" + pluginName + "/" + pluginName +
".jar").toURI().toURL()}, getClass().getClassLoader());
} catch (MalformedURLException e) {
e.printStackTrace();
}
Class<?> clazz = null;
try {
clazz = Class.forName("com.sample.Specific", true, loader);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Method method = null;
try {
method = clazz.getMethod("run",new Class[]{});
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
method.invoke(clazz.newinstance,new Object[]{});
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
Specific Class is follow :
package com.sample
#Service
public class Specific {
#Autowired
private FD fd;
public void run(){
fd.init();
}
}
#Autowired FD comes to be null. Can anyone give me some solution as i also know new operator will not work for #autowired. As i am loading class with new instance then only it becomes null. Can anyone guide me in this thing
Spring has its own way to provide you new objects. As long as you're consistent using #Autowired and #Component/#Service/#Repository/#Controller there should be no problem
And since all "business" object instantiation is handled by Spring you should never use new. If you have no other way of getting an instance (something I realy doubt about it) you can use ApplicationContext.getBean() but as I said, in most cases this is not required (and this is also a bad practice)
If you need several instances of a class instead of injecting them (by using #Autowired) you can inject a Provider<T>
UPDATE
Since the class is known at runtime you need to inject an ApplicationContext and use it to get the bean:
public class TheClassWhereYouAreCreatingTheObject {
#Autowired
private ApplicationContext context; // You definitely need this
public void theMethodWhereYouAreCreatingTheObject() {
Class<?> clazz = ... // getting the object class
Object instance = context.getBean(clazz); // getting and instance trough Spring
// If you know that kind of object you will get cast it at call its methods
((Specific) instance).run();
// If you know anything about the class you will have to use reflection
Method method = clazz.getMethod("run", new Class[]{});
method.invoke(instance, new Object[]{});
}
}
Add Specific Service bean inside your main class. As long as the service is inside one your component scan packages then you shall be fine. Do not use new operator.
#Autowired
private Specific specific;
If you want to take advantage of autowiring then I think we have to think from spring terms.
you can use Beanutils to create a new instance and play with reflections supporting spring features.
Please go through below methods:
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/BeanUtils.html

How can I go about checking whether a particular Stage is an instance of a particular Controller Class

How can I go about checking whether a particular Stage is an instance of a particular Controller Class?
For example:
I have a Stage stage, and the only information I have is that the stage.getScene().getRoot() is an instance of a VBox.
I, however, could get the Controller class of a Stage via:
public Object loadController(String url) {
try {
loader = new FXMLLoader(getClass().getResource(url));
loader.load();
return loader.getController();
} catch (IOException ex) {
Logger.getLogger(AppFactory.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
The main problem I have is that there is no way to get the url of the stage.getScene().getRoot()

JAVA creating an event list from a text file

I have a controller class, it basically holds an event list.
ArrayList <Event> eventList = new ArrayList<>();
The controller has an addEvent(Event e) method.
I've extended the controller class to be a specific kind of controller, and extended event to provide specific kinds of events for my new controller as inner classes.
public class NewController extends Controller{
//.. controller code/methods
class SpecificEvent extends Event{
//..
}
}
I've hard coded my controller to work as I intended, but I wanted to be able to make a configuration file that would populate my event list.
I made a .txt file with a list of events:
Event=SpecificEvent, Arg1=<Integer>val, .. ArgN=<?>val, Event=SpecificEventN, ArgN=<?>val
I filtered out the event class name and arguments into a list:
fileContents.stream()
.forEach(s -> {
Scanner sc = new Scanner(s)
.useDelimiter("=|,");
while (sc.hasNext()){
Scanner sc2 = new Scanner(sc.next()).useDelimiter("[//w]");
args.add(sc.next());
}
});
My problem is that events have different constructor argument types and lengths; I don't know how to build them from my file. I'm new to this kind of work and I figure this is run of the mill implementation.
Do I use the Reflect package? Please help. I was thinking off an Event Factory?
Thanks for the community help. This factory will do the job when provided a string array argument, {String classname, args.... }
/**
* ClassFactory method, build an event.
*
* #param arguments Required arguments to build an Event.
* #return Built event.
* #throws java.lang.ClassNotFoundException
*/
public Event buildEvent(String [] arguments) throws ClassNotFoundException {
Class<?>[] argumentTypes = {};
Object[] parameters = {};
try {
//define the class type from the first argument
Class<?> eventClass
= Class.forName(packageName + arguments[0]);
if (arguments.length() > 1) {
argumentTypes = new Class<?>[]{Long.TYPE};
parameters = new Object[]{Long.parseLong(arguments[1])};
Constructor<?> constructor
= eventClass.getDeclaredConstructor(argumentTypes);
Object instance = constructor.newInstance(parameters);
return ((Event) instance);
//default
} else {
Constructor<?> constructor
= eventClass.getDeclaredConstructor();
Object instance = constructor.newInstance();
return ((Event) instance);
}
} catch (ClassNotFoundException cnfe) {
System.out.println("Class not available in this package.");
} catch (NoSuchMethodException |
SecurityException |
InstantiationException |
IllegalAccessException |
IllegalArgumentException |
InvocationTargetException e) {
log.log(Level.SEVERE, "Class Builder: {0}", e.getMessage());
}
return null;
}

Cannot get JAXBContext?

In my java project i have a jar that i generated with some classes. I am able to instantiate the instance of the class that is in my jar:
Alert a = new Alert();
But wen i try to do this:
JAXBContext context = JAXBContext.newInstance(Alert.class);
I get run time exception like this:
java.lang.InternalError:
Error occured while invoking reflection on target classes. Make sure all referenced classes are on classpath: interface javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter
Exception: null
Any idea what could be the issue?
Thank you
This happened to me as I had defined XmlAdapter implementations that were in a different JAR and not on the classpath. When trying to create the JAXBContext, it needs these adapters used by the JAXB type. Now that I figured this out, the message makes more sense, but is still very cryptic. XmlJavaTypeAdapter is the annotation interface and the code fails to call the value() method of the annotation as it returns Class<? extends XmlAdapter>, a class type which is not defined on the classpath.
If you look at the code that throws the exception, this is impossible:
public Class More ...getClassValue(Annotation a, String name) {
try {
return (Class)a.annotationType().getMethod(name).invoke(a);
} catch (IllegalAccessException e) {
// impossible
throw new IllegalAccessError(e.getMessage());
} catch (InvocationTargetException e) {
// impossible
throw new InternalError(e.getMessage());
} catch (NoSuchMethodException e) {
throw new NoSuchMethodError(e.getMessage());
}
}
Would be nice if the cause of the exception was not lost.

Setting an instance to null or create a new instance with new

Does this:
// Class 'Refresh' inherits class 'Thread'
Thread refresh = new Refresh(paramOne);
...
refresh = null;
refresh = new Refresh(paramTwo);
And this:
// Class 'Refresh' inherits class 'Thread'
Thread refresh = new Refresh(paramOne);
...
refresh = new Refresh(paramTwo);
Have the same result?
Does assigning a new class instance on an existing object null out the first class instance?
Actually they don't quite have the same result.
In the first case if an exception is thrown while constructing new Refresh() then refresh will still be null. In the second case refresh will still be the first object constructed.
Assuming new Refresh(paramTwo) does not ever throw an exception or the refresh variable is not visible outside the current context then the two are equivalent.
public class Main{
static class Boom {
Boom(boolean noBoom) {
}
Boom() {
throw new RuntimeException();
}
}
public static void main(String[] args){
Boom boom1 = new Boom(true);
try {
boom1=null;
boom1=new Boom();
} catch (Exception ex) {};
System.out.println(boom1);
Boom boom2 = new Boom(true);
try {
boom2=new Boom();
} catch (Exception ex) {};
System.out.println(boom2);
}
}
Try it:
http://www.tryjava8.com/app/snippets/52cd952fe4b00bdc99e8ab38
Result:
null
Main$Boom#d35755c
The short answer is yes. Assuming no other references to the original value remain, that value is eligible for garbage collection either way.
There is no difference.
refresh = null;
Is redundant here. It wont make any difference.
When you write
refresh = new Refresh(paramTwo);
Existing reference is overriding anyway. So no matter what it is previously.Weather it is null or still holding some instance won't matters.

Categories

Resources