I could need some help with a problem I have with Java's generics.
I constructed a little example for to show what I mean.
Handler
package generalizingTest;
public class Handler<S extends Server<?>> {
public S server;
public Handler(S server) {
this.server = server;
}
}
SubHandler
package generalizingTest;
public class SubHandler<S extends Server<?>> extends Handler<S> {
public SubHandler(S server) {
super(server);
}
public void subHandlerMethod() {
}
}
Server
package generalizingTest;
import java.util.ArrayList;
public class Server<H extends Handler<?>> {
public ArrayList<H> handlers;
public Server() {
handlers = new ArrayList<H>();
}
public void addHandler(H c) {
handlers.add(c);
}
}
SubServer
package generalizingTest;
public class SubServer<H extends Handler<?>> extends Server<H> {
public void subServerMethod() {
}
}
Startup
package generalizingTest;
public class Startup {
public static void main(String[] args) {
Server<Handler<?>> serverWHandler = new Server<Handler<?>>();
Server<SubHandler<?>> serverWSubHandler = new Server<SubHandler<?>>();
SubServer<Handler<?>> subServerWHandler = new SubServer<Handler<?>>();
SubServer<SubHandler<?>> subServerWSubHandler = new SubServer<SubHandler<?>>();
Handler<Server<?>> handlerWServer = new Handler<Server<?>>(serverWHandler);
Handler<SubServer<?>> handlerWSubServer = new Handler<SubServer<?>>(subServerWHandler);
SubHandler<Server<?>> subHandlerWServer = new SubHandler<Server<?>>(serverWSubHandler);
SubHandler<SubServer<?>> subHandlerWSubServer = new SubHandler<SubServer<?>>(subServerWSubHandler);
serverWHandler.addHandler(handlerWServer);
subServerWHandler.addHandler(handlerWSubServer);
serverWSubHandler.addHandler(subHandlerWServer);
subServerWSubHandler.addHandler(subHandlerWSubServer);
subServerWHandler.subServerMethod();
subServerWSubHandler.subServerMethod();
handlerWSubServer.server.subServerMethod();
subHandlerWSubServer.server.subServerMethod();
subHandlerWServer.subHandlerMethod();
subHandlerWSubServer.subHandlerMethod();
System.out.println(subHandlerWSubServer.server.handlers.get(0).getClass().getName()); // SubHandler
//produces an error:
/*
* Unresolved compilation problem:
* The method subHandlerMethod() is undefined for the type Handler<capture#9-of ?>
*/
//subHandlerWSubServer.server.handlers.get(0).subHandlerMethod();
}
}
I just started learning about generics. They seem to be efficient but I am not sure if I solved the problem of the generics loop () correctly with the wildcard and why those errors occur.
I really hope someone can help me out.
EDIT:
So it seems like I did not highlighted the initial problem enough.
The following should be possible in any depth:
subHandlerWSubServer.server.handlers.get(0).server.handlers.get(0).server.handlers.get(0). ... .server.handlers.get(0).subHandlerMethod();
EDIT:
So this problem seems not to be solvable due to an endless loop of definition or the missing self value, see Siguza’s anwser.
Here is the discussion between Siguza, user889742 and myself about this topic.
If I understood you correctly, if you have a Handler<S> you want all handlers on that server to be of type Handler<S>, right?
For that, S.add() would have to only accept objects of type Handler<S>. But in order to implement that in the base class Server, you would need S, so that:
public class Server<H>
{
public ArrayList<H<S>> handlers;
public Server()
{
handlers = new ArrayList<H<S>>();
}
public void addHandler(H<S> c)
{
handlers.add(c);
}
}
The only problem with this is that S is not defined, and you cannot easily define it. What you would need is something that, in the context of Server, means Server, and in the context of SubServer, means SubServer. Basically this.getClass(), but as a compile-time type expression. If Java had a keyword for that, say self, you could use it like this:
public class Server<H>
{
public ArrayList<H<self>> handlers;
public Server()
{
handlers = new ArrayList<H<self>>();
}
public void addHandler(H<self> c)
{
handlers.add(c);
}
}
Then Server.add() would take Handler<Server>, and SubServer.add() would take Handler<SubServer>.
Sadly, Java has no such thing, therefore what you're trying to do is not possible this way.
Java does many things well.
Generics aren't one of them.
It could work with a redesign like this. You would not be able to use Server as your starting point, since it would require generic arguments leading to a recursive definition again. Instead, start with ServerInfo. As you can check it works, but I think it might be a bit cumbersome and not intuitive.
class Server
{
}
class Handler
{
}
class SubServer extends Server
{
}
class SubHandler extends Handler
{
public void subHandlerMethod(){}
}
class HandlerInfo<S extends Server, H extends Handler>
{
ServerInfo<S,H> serverInfo;
H handler;
}
class ServerInfo<S extends Server, H extends Handler>
{
S server;
ArrayList<HandlerInfo<S,H>> handlerInfo = new ArrayList<>();
}
public class Example {
public static void main(String[] args) {
Server s = new Server();
SubHandler h = new SubHandler();
ServerInfo<Server,SubHandler> serverInfo = new ServerInfo<>();
HandlerInfo<Server,SubHandler> handlerInfo = new HandlerInfo<>();
handlerInfo.serverInfo = serverInfo;
handlerInfo.handler = h;
serverInfo.server = s;
serverInfo.handlerInfo.add(handlerInfo);
serverInfo.handlerInfo.get(0).serverInfo.handlerInfo.get(0).handler.subHandlerMethod();
}
}
Edit:
You could simply restrict SubServers to only accept SubHandlers
Subserver<H extends SubHandler> extends Server<H>
When you do that you will see that the compilation error goes away.
But I understand you want to define some Servers that allow only subHandlers, and some subHandlers that allow only Servers. ( Seems strange to me ), and then reflexive relationship H<->S gives you trouble, leading to generic type recursion.
While I think it's strange to mix Server->Subhandler and Handler->SubServer , you could accomplish an unrestricted 2 way relationship as you want by extracting interfaces like this: ( try it, it works )
interface IHandler
{
}
interface IServer
{
}
interface ISubServer extends IServer
{
public void subServerMethod();
}
interface ISubHandler extends IHandler
{
public void subHandlerMethod();
}
class Handler<S extends IServer> implements IHandler {
public S server;
public Handler(S server) {
this.server = server;
}
}
class SubHandler<S extends IServer> extends Handler<S> implements ISubHandler {
public SubHandler(S server) {
super(server);
}
public void subHandlerMethod() {
}
}
class Server<H extends IHandler> implements IServer{
public ArrayList<H> handlers;
public Server() {
handlers = new ArrayList<H>();
}
public void addHandler(H c) {
handlers.add(c);
}
}
class SubServer<H extends IHandler> extends Server<H> implements ISubServer {
public void subServerMethod() {
}
}
public class Example {
public static void main(String[] args) {
Server<IHandler> serverWHandler = new Server<IHandler>();
Server<ISubHandler> serverWSubHandler = new Server<ISubHandler>();
SubServer<IHandler> subServerWHandler = new SubServer<IHandler>();
SubServer<ISubHandler> subServerWSubHandler = new SubServer<ISubHandler>();
Handler<IServer> handlerWServer = new Handler<IServer>(serverWHandler);
Handler<ISubServer> handlerWSubServer = new Handler<ISubServer>(subServerWHandler);
SubHandler<Server<ISubHandler>> subHandlerWServer = new SubHandler<Server<ISubHandler>>(serverWSubHandler);
SubHandler<SubServer<ISubHandler>> subHandlerWSubServer = new SubHandler<SubServer<ISubHandler>>(subServerWSubHandler);
serverWHandler.addHandler(handlerWServer);
subServerWHandler.addHandler(handlerWSubServer);
serverWSubHandler.addHandler(subHandlerWServer);
subServerWSubHandler.addHandler(subHandlerWSubServer);
subServerWHandler.subServerMethod();
subServerWSubHandler.subServerMethod();
handlerWSubServer.server.subServerMethod();
subHandlerWSubServer.server.subServerMethod();
subHandlerWServer.subHandlerMethod();
subHandlerWSubServer.subHandlerMethod();
System.out.println(subHandlerWSubServer.server.handlers.get(0).getClass().getName()); // SubHandler
//no longer produces an error:
subHandlerWSubServer.server.handlers.get(0).subHandlerMethod();
}
}
and remember, anytime your problem is a reflexive relationship A<->B , not just with generics, you can extract IA and IB so that A->IB and B-> IA
Related
I am new to Java -- coming from the PHP Python world. I am sure this is a simple question and that I'm missing something basic, but after a couple hours of searching and tinkering, I can't figure it out.
I have a Path class that keeps to points, an In and an Out:
public class Path<In extends PointInterface, Out extends PointInterface> {
private In in;
private Out out;
public Path(In in, Out out) {
this.in = in;
this.out = out;
}
public In getIn() {
return in;
}
public Out getOut() {
return out;
}
}
I have many implementations of PointInterface, for now, let's say Queue and Endpoint.
I want to be able to instantiate a Path object with any combination of those two PointInterface implementations.
That's all pretty easy.
Path path = new Path<>(new Endpoint(), new Queue());
The Problem Is that each of those implementations has its own handler for both In and Out. So, inside that EndpointInHandler I can be certain that path.getIn() will return an Endpoint (which implements PointInterface).
But, when I try Endpoint in = path.getIn(); inside that method, I get an Incompatible Types error saying that it required Endpoint but found PointInterface.
Endpoint implements PointInterface.
I have tried:
defining generics in the handlers like InHandlerInterface<Endpoint>
not using the extends logic, but then I have the same problem with Object
using Abstract classes instead of interfaces
and a couple other things.
Can anyone help me understand what I'm missing? Much thanks :)
Code Sample
Inside my Main method:
Path path = new Path<>(new Endpoint(), new Queue());
InHandlerInterface handler = path.getIn().getInHandler(); // returns the EndpointInHandler
handler.handle(path);
Path detailed above.
PointInterface:
public interface PointInterface {
InHandlerInterface getInHandler();
}
Endpoint:
public class Endpoint implements PointInterface {
#Override
public InHandlerInterface getInHandler() {
return new EndpointInHandler();
}
public String specificToEndpoint() {
return "Whatever";
}
}
InHandlerInterface:
public interface InHandlerInterface {
void handle(Path path);
}
EndpointInHandler:
public class EndpointInHandler implements InHandlerInterface {
#Override
public void handle(Path path) {
Endpoint in = path.getIn(); // This is giving me the Incompatible types error
String whatever = in.specificToEndpoint();
}
}
When you do Path path = new Path<>(new Endpoint(), new Queue()), you have effectively lost the type of the generics.
You need to write it as Path<EndPoint, Queue> path = new Path<>(new Endpoint(), new Queue()) so that the compiler is aware what the actual types the generics are referring.
Update
Looking again, I realized that you need to put generics everywhere. It may look weird to see generics appearing everywhere, but this is the way to ensure compile-time type safety. Doing this, you would not need any explicit casts.
Path<Endpoint, Queue> path = new Path<>(new Endpoint(), new Queue());
InHandlerInterface<Endpoint> handler = path.getIn().getInHandler(); // returns the EndpointInHandler
handler.handle(path);
PointInterface:
public interface PointInterface<T extends PointInterface> {
InHandlerInterface<T> getInHandler();
}
Endpoint:
public class Endpoint implements PointInterface<Endpoint> {
#Override
public InHandlerInterface<Endpoint> getInHandler() {
return new EndpointInHandler<>();
}
public String specificToEndpoint() {
return "Whatever";
}
}
InHandlerInterface:
public interface InHandlerInterface<T extends PointInterface<T>> {
void handle(Path<T, ?> path);
}
EndpointInHandler:
public class EndpointInHandler implements InHandlerInterface<Endpoint> {
#Override
public void handle(Path<Endpoint, ?> path) {
Endpoint in = path.getIn(); // This is naturally type safe, and compiler won't complain
String whatever = in.specificToEndpoint();
}
}
Hi ive been reading on some similar topics here but none of them answer my question. Some say you cant even do this which is not a good thing since I cant finnish my course in that case.
Heres som simple code. Think of each block as a separate class.
public interface Interface {
void printMessage(String meddelande);
}
public class Model implements Interface {
String message = "hej!";
public static void main(String[] args) {
Model model1 = new Model();
View view1 = new View();
model1.printMessage(model1.message); //Ska jag anropa funktionen såhär ens?
}
public void printMessage(String str) {
}
}
public class View implements Interface {
printMessage(String str) {
}
}
So, how is it now possible to tel the view to print this string from the model class without the classes knowing about each other? Its not allowed to send a reference of the model-objekt to the view-object. ; (
Define an Interface:
public interface MyInterface {
void printMessage(String str);
}
Define a class that can trigger the notification:
public class ClassNotifier {
MyInterface mInterface;
public ClassNotifier(MyInterface mInterface) {
this.mInterface = mInterface;
}
public void triggerTheMsg(String msg) {
if (mInterface != null) {
mInterface.printMessage(msg);
}
}
}
Define a class that will be informed:
public class InformedClass implements MyInterface {
public static void main(String[] args) throws Exception {
InformedClass c = new InformedClass();
ClassNotifier cn = new ClassNotifier(c);
}
#Override
public void printMessage(String newMsg) {
System.out.println("A new msg is here: " + newMsg);
}
}
How does it works?:
this is named a callback parttern, the class ClassNotifier has a reference to the interface MyInterface, which is impl. by Informed class to, so every time the ClassNotifier calls the method printMessage, the method printMessage in the class Informed will be triggered too.
I advice you to use dependency injection, for example:
public class Model {
String message = "hej!";
Interface printer;
public void Model(Interface printer) {
printer = printer;
}
public static void main(String[] args) {
Model model1 = new Model(new View());
model1.printMessage(model1.message);
}
public void printMessage(String str) {
printer.printMessage(str);
}
}
I am trying to use RabbitMQ and based on different message, different implements should be called.
I set the message format as of JSON, and there is a field "callType", the value of it is the class name implements a common interface. e.g, all implementations have implements interface "Task", and I have implementation of "TaskImp1","TaskImp2","TaskImp3".
So the code should be like
if (callType=="TaskImp1")
((Task)TaskImp1).runTask()
if (callType=="TaskImp2")
((Task)TaskImp2).runTask()
if (callType=="TaskImp3")
((Task)TaskImp3).runTask()
But could it be more flexible? If later I develop a new one "TaskImp4", I don't want to change the calling code, is it possible to have java automatically pick the right implementation since the callType is actually the class name of the implementation.
Yes, for example, through Java reflection (What is reflection and why is it useful?). Reflection has a performance cost though (Java Reflection Performance)
Sure: put your Task instances in a map:
private Map<String, Task> tasksByName = new HashMap<>();
...
tasksByName.put("TaskImp1", new TaskImp1());
tasksByName.put("TaskImp2", new TaskImp2());
tasksByName.put("TaskImp3", new TaskImp3());
...
String callType = message.getCallType();
Task task = tasksByName.get(callType);
task.runTask();
Also, read How do I compare strings in Java?
You have an opportunity to use Strategy here. So for e.g. you could do like:
public class MyTask {
private Task task;
public MyTask(Task task) {
this.task = task;
}
public void doSomething() {
task.runTask();
}
public static void main(String args[]) {
MyTask task = new MyTask(new TaskImpl1());//or even you could use setTask() api to inject task at runtime rather than doing cast on compile time.
task.doSomething();
task = new MyTask(new TaskImpl2());
task.doSomething();
task = new MyTask(new TaskImpl3());
task.doSomething();
}
}
In this way you could make your code extensible. Tomorrow if you have taskImpl4, you could code it independently and inject in MyTask without even touching MyTask class implementation.
As #ovdsrn already said you can use reflection. Simple example would be something like (the key is getTask static method. Also, note that, when you are using Class.forName you must specify whole "path" (package) for your class)
// ITask.java
package main;
public interface ITask {
void doSomething();
}
// Task1.java
package main;
public class Task1 implements ITask {
#Override
public void doSomething() {
System.out.println("Task1");
}
}
// Task2.java
package main;
public class Task2 implements ITask {
#Override
public void doSomething() {
System.out.println("Task2");
}
}
// main
package main;
public class JavaTest {
private static ITask getTask(String name) {
try {
Class<?> cls = Class.forName(name);
Object clsInstance = (Object) cls.newInstance();
return (ITask)clsInstance;
} catch (Exception e) { // you can handle here only specific exceptions
return null;
}
}
public static void main(String[] args) {
String name = args.length > 0 ? args[0] : "Task2";
ITask task = getTask("main." + name);
if (task != null) {
task.doSomething();
}
else {
System.out.println("can not make instance of class: " + name);
}
}
}
I'm working on a game engine, and the last question I had regarding this was what good way I can use to make "observers" or listeners. A user suggested that I should use Java's EventObject class to inherit from and make a Listener interface. However, this didn't provide me with good flexibility.
Here is the Handler annotation to state that a method is an event handler in a listener:
#Retention(RetentionPolicy.CLASS)
#Target(ElementType.METHOD)
public #interface Handler {}
Here is the base class for Event, which is basically the same as EventObject (but I'll add abstract methods sooner or later):
public abstract class Event {
private Object source;
public Event(Object source) {
this.source = source;
}
public Object getSource() {
return source;
}
}
Here is the Listener class, which is empty:
public interface Listener {}
Here is the ListenerHandler class, used to handle all listeners. You register and unregister them here. I'll edit the register/unregister methods later for a better use:
public class ListenerHandler {
private ArrayList<Listener> listeners;
public ListenerHandler() {
this.listeners = new ArrayList<Listener>();
}
public void registerListener(Listener l) {
listeners.add(l);
}
public void unregisterListener(Listener l) {
listeners.remove(l);
}
public void onEvent(Event event) {
for(Listener l : listeners) {
Class<?> c = l.getClass();
Method[] methods = c.getDeclaredMethods();
for(Method m : methods) {
if(m.isAccessible()) {
if(m.isAnnotationPresent(Handler.class)) {
Class<?>[] params = m.getParameterTypes();
if(params.length > 1) {
continue;
}
Class<?> par = params[0];
if(par.getSuperclass().equals(Event.class)) {
try {
m.invoke(this, event);
}catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
}
}
}
}
From what I heard, it's a use of a lot of memory in order to get all methods of a class. I'm not going to assume this is the case, but I'm sure there is a better way as this will be a game engine with many components and such.
I'd like to know the best way to implement this, or if I'm doing it right. I'd also like to know if anyone can help me improve this in any way without hogging memory usage by the game (as of now it's not a big deal -- the "game engine" is not even close to rendering anything yet)
I tried to keep it a very simple example and will comment with different ideas to it:
First meet the Achievement class:
import java.util.Observable;
public class Achievement extends Observable {
public static class AchievementDetails {}
public Achievement() {
addObserver(EventsListener.getInstance());
}
public void achievementReached() {
AchievementDetails achievemetDetails = null;
setChanged();
notifyObservers(achievemetDetails);
}
}
And then the events listener class:
import com.test.Achievement.AchievementDetails;
public class EventsListener implements Observer {
private static EventsListener instance = new EventsListener();
public static EventsListener getInstance() {
return instance;
}
#Override
public void update(Observable o, Object arg) {
if(o instanceof Achievement) {
AchievementDetails achievemetDetails = (AchievementDetails) arg;
//do some logic here
}
}
}
The only one thing that is missing is to create an instance of your achievement (which register the EventsListener to itself) and handle the life cycle of it.
I am developing a web application in jsf
I have these classes
Abstract:
RepositoryBase
ManagedBeanCRUD
EntityBase
Classes:
Client extends EntityBase
ClientRepository extends RepositoryBase
ClientManagedBean extends ManagedBeanCRUD
However I am having trouble to implement a save method at ManagedBeanCRUD
during this method I need a Repository, so I have a RepositoryBase rep = repositoryfactory.getFactory((entity.getClass()));
I tried to implement the repositoryFactory in many ways, but still without success.
Anyone has any idea how I could do this???
thank you in advance
public class ManagedBeanCRUD < T extends EntityBase> () {
protected T newEntity;
public void save() {
Repositoryfactory factory = new Repositoryfactory();
RepositoryBase<T> rep = factory.getFactory((entity.getClass()));
rep.persiste(newEntity);
}
}
public class FactoryRepository < T extends EntityBase> () {
public RepositoryBase<T> getFactory(Class newEntity) {
if(newEntity == Client.class) {
return new ClientRepository();
} else {
System.out.println("error");
}
}
}
public class ClientManagedBean extends CRUDBean<Client> {
private static final long serialVersionUID = 1L;
private Clietn client = new Client();
public void setSalve(){
this.setNewEntity(this.client);
this.salvar();
this.client = new Client();
}
}
public class ClientRepository extends RepositoryBase{
#Override
protected Class<Client> getRuntimeClass() {
return Client.class;
}
}