Question

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.

Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top