0

I am stuck in a situation where I decided early on not to create a specific graph with Guice. I need a factory, but I cannot figure out how to build it.

What I have achieved is a session aware game object management system.

All objects that need to be involved in this work fine.

They are all created through injection, providers, guice factories, etc.

The one object that I really need to be able to manage at this level is Items.

Items is also the one object I do not have guice creating.

Items also have a complex class hierarchy that the client knows up front, but the platform code does not. In my original design I built my own factory to be able to use my guicified components to correctly build these objects.

This worked fine up till now, since these objects must participate in the management layer, I need to find a guicy solution.

Here is the current implementation:

abstract class Item{
  public Item(ItemID item){
    ...
  }
  ...
}

class MyItem extends Item{
   ...
}

class MyOtherItem extends MyItem{
   ...
}

class MyFavoriteItem extends Item{
   ...
}

My current non guice implementation looks a bit like this

class ItemFactory{
   //this sequence generator is plugged into my persistance layer. Allows for generating
   //restful api calls for a specific item.
   @Inject
   private SequenceGenerator sequenceGenerator;

   public ItemID getNextItemID(){
     return sequenceGenerator.generateNextItemID();
   }

   //NOTE: these created objects do not participate in AOP
   //since they are not created by guice
   public <I extends Item> I createItem(Class<I> type){
     Item myItem = type.getConstructor(ItemID.class).newInstance(getNextItemID());
     return (I)myItem;
   }
}

The subtypes are completely unknown to me, and are usually provided by a client module. I have a few annotations that with any guice created objects, I can provide managed state in a game framework I am developing.

It works great for all objects except item... since they are not guice created objects.

I would much rather something like this:

class MyItem extends Item{
  @Inject
  public MyItem(@Assisted ItemID itemID);
}

interface MyGuiceFactory{
  public <I extends Item> I createItem(Class<I> type, ItemID itemID);
}

class MyGuiceModule extends AbstractModule{
  public void configure(){
    install(new FactoryModuleBuilder().build(MyGuiceFactory.class));
  }
}

class MyGuiceApp{
  @Inject
  private MyGuiceFactory factory;

  private SequenceGenerator sequenceGenerator

  @Inject
  public MyGuiceApp(SequenceGenerator generator){
    sequenceGenerator = generator;
  }

  public ItemID getNextItemID(){
    return sequenceGenerator.generateNextSequenceID(ItemID.class);
  }

  public <I extends Item> I createItem(Class<I> type){
    return (I)factory.createItem(type, getNextItemID());
  }
}

Since Guice cannot use the generic static type as a key, it doesn't know what to build. Since I cant bind it to anything specific, or ask it to be bound to anything specific

I am stuck not being able to build it with guice. However I have some AOP code that needs this to be created by guice.

If I am able to create subtypes from my application, those subtypes can participate in my managed game state aop layer.

Any advice would be a great help.

Any advice on rephrasing the question would also be greatly appreciated.

AnthonyJClink
  • 970
  • 1
  • 10
  • 31
  • I don't understand why `ItemFactory` has two methods. How do `ItemID` and `createItem` interact? – kan Apr 08 '13 at 13:51
  • Also, provide any usecases you want to achieve. – kan Apr 08 '13 at 14:04
  • I have provided the edits, hopefully that is more clear. – AnthonyJClink Apr 08 '13 at 14:31
  • A type literal may be what I need... I just cant figure out where to put it? – AnthonyJClink Apr 08 '13 at 14:59
  • I don't understand why do you need the factory. Could you show a code which uses the stuff? I suspect you just need to have a `Provider myItemProvider` or `Provider myOtherItemProver` injections instead of the factory. – kan Apr 08 '13 at 15:25
  • With the factory I do not need to know the subtype of the item being created, and I can pass parameters to the constructor. – AnthonyJClink Apr 08 '13 at 15:32
  • Problem is I have N number of subtypes and I don't know many of them up front. The code where I use my current non guice factory is at http://github.com/AnthonyClink/Clinkworks-GameEngine/blob/master/GameEngine_Core/com/clinkworks/gameengine/api/GameBase.java – AnthonyJClink Apr 08 '13 at 15:35
  • its being used here https://github.com/AnthonyClink/Drugwars/blob/master/DrugWars/com/drugwars/api/Playground.java... I need that AK47 to be created by Guice instead of by me. If the provider is the solution, I cant figure out how to pass parameters to it. – AnthonyJClink Apr 08 '13 at 15:41
  • Pass type parameters I guess is what im asking. Even with a single provider, how can I .... give what they want?... upcast... whatever you want to call it. provide an item of type I extends Item – AnthonyJClink Apr 08 '13 at 15:51
  • I think you should somehow to avoid passing `.class` to a factory, e.g. you could have map of factories, or qualified factories for each type. Could you give more details what are you trying to achieve? – kan Apr 08 '13 at 15:52
  • I just need some kinda guice passthrough. – AnthonyJClink Apr 08 '13 at 15:54
  • I am trying to achieve the ability for clients to create their own item types, and have those items be managed by the Game object via the StatManager and StatContainerInjectors. – AnthonyJClink Apr 08 '13 at 15:56
  • The only thing I am missing is the ability to return parameterized instances. //probably a better name for this. – AnthonyJClink Apr 08 '13 at 15:56
  • As I see, the ` I createItem(Class itemType)` is equivalent to `Provider provider` and then `provider.get()`. Could you show example of how do you use createItem? How the `Class` is provided? – kan Apr 08 '13 at 16:01
  • @kan I create the GameManager which is my app class `GameManager manager = GameModule.getGameManager()` `Game game = gameManager.createGame();` Weapon extends Item `Weapon weapon = game.createItem(AK47.class //extends Weapon)` all I need is the `game.createItem(Class itemType)`'s resulting Object to be created by guice. I cannot figure out an explicit way to do this. So to answer your question, it is client code that provides the itemtype – AnthonyJClink Apr 08 '13 at 16:42
  • @Kan There must be some provider trick, or typeliteral solution, that will do the same thing as the parameterized method in the game class. – AnthonyJClink Apr 08 '13 at 16:48

1 Answers1

1

As you see, your game is a homegrown ioc-container itself. As I understand, somewhere you have

class AClass
{
  @Inject private Game game;
  void method() {
    Weapon weapon = game.createItem(AK47.class);
    weapon.shoot();
  }
}

what I mean by using Provider is:

class AClass
{ 
  @Inject private Provider<AK47> ak47Provider;
  void method() {
    Weapon weapon = ak47Provider.get();
    weapon.shoot();
  }
}

When you just need to configure your injector modules to bind all providers you could have in an application.

The same effect you could do if you inject an Injector into the Game and use it as an object factory:

class GameBase
{
  @Inject private Injector injector;
  public <I extends Item> I createItem(Class<I> itemType){
    return injector.getInstance(itemType);
  }
}

Do you see that com.google.inject.Injector#getInstance has exactly the same signature as yours createItem?

But I prefer the first variant, it looks more cleaner and reduces dependencies.

kan
  • 26,120
  • 6
  • 61
  • 96
  • I guess where im stuck then... I don't know what package a subtype is going to be, I don't have a registry for them... so at bind time... do I need to do someting like `for(eachPossibleSubtype : allPossibleClassesInClassHierarchy){ bind(eachPossibleSubtype).to(item.class)}` ?. My game object produces items at the users request. It could be a brand new module... if they add thier own item types later, I defenently couldn't know what they are... – AnthonyJClink Apr 08 '13 at 22:01
  • I am building a kind of game creator studio. The only item I provide is the supertype. A compeltly new project called MyGameImplementation can create thier own subtypes, I need those subtypes to be produced by guice somehow and returned as the generic type of the concrete class passed in... I need to produce it with guice so that I can keep track of quantities ... other itemy stuff that I give for free with my library. passing in the injector seems workable, but I don't like the idea of the injector creating anything else but my game manager. – AnthonyJClink Apr 08 '13 at 22:44
  • Wait, I didn't take enough time to read what you were really writing. Is it possible with the provider to give it the sig of something like Provider extends Item>? – AnthonyJClink Apr 08 '13 at 22:46
  • the seneario is, maybe the client code creates a vendor, and they just want to pass in a few random item classes, maybe a list of classes to create in their shopkeepers inventory... Or like how in jpa you do query.find(TypeToFind.class) – AnthonyJClink Apr 08 '13 at 22:48
  • 1
    You don't know anything about Item subtypes, then it should be done by users. So, just allow to add user defined guice modules to your system. You could just provide list of standard modules and ask users to build an injector including all required modules, user defined too. Or you could make kind of plugin arch by scanning for module classes marked with an annotation, or using `java.util.ServiceLoader`. Also, you could try to replace inheritance by composition. No, `Provider...>` doesn't make sense. – kan Apr 08 '13 at 22:56
  • I think I am missing some base fundemental concept somewhere. Providers have always confused me and I like classes with parameters so I have always use the FactoryBuilder module class. – AnthonyJClink Apr 08 '13 at 23:00
  • The missing thing is - you don't know anything about item subclasses, but you want to make an universal factory for it. Allow users do it how they need it. – kan Apr 08 '13 at 23:08
  • This is the correct solution, on both parts. And since neither answer fits the api I have in mind, a redesign is in order and stick to a more bean model with the items. Thank you for assisting me in finding the correct solution and for being so patient with me. – AnthonyJClink Apr 09 '13 at 00:01