Hi

The code below provides a working example of what I try to do.

I have a tree-like structure where the node implementation depends on the content object it should contain. Each node constructor gets node content as assisted value and a number of node factories of specific types that depend on types of child nodes this node can have.

So I have the base Node<E> class and some concrete implementations. The real guice module is configured with a lot of "install(FactoryModuleBuilder).implement(Node<XXXXX>, XXXXXNode.class).build(NodeFactory<XXXXX>)" for each XXXXX content type, and everything works fine until I have a node that can contain child nodes of the its own type.

The constructor of such a node (like IntegerNode in the example below) has assisted parameter for the node content and factory parameter that basically should create nodes of the same type as this node. The problem is if the factory is used from the constructor it results in ProvisionException with "Tried proxying TestGuiceModule$Node to support a circular dependency, but it is not an interface." message (the second try at creating nodes in the example code below), while using the same factory object after the node constructor finishes works (the first try at creating nodes in the code below).

If the node children have a types different from the node type then using corresponding factories even from the node constructor works without any errors. And if some children have the same type as the node then the approach where node constructor stores factories in the member variables and all children nodes are created after the node constructor finishes provides a workaround.

But why does the Guice decides to detect that circular dependency? The test code shows that the factory object is actually the same object instance so it is presumably fully constructed and ready to create new node instances. Why using the factory from the constructor of the type this factory creates (actually, from the constructor of the instance this factory just have created) results in exception?

=== test code ===
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.FactoryModuleBuilder;

public class TestGuiceModule {

   public static void main( String[] args ) {
       Injector injector = Guice.createInjector( new AbstractModule() {
           @Override
           protected void configure() {
               install( new FactoryModuleBuilder()
.implement( new TypeLiteral<Node<Integer>>() {}, IntegerNode.class ) .build( new TypeLiteral<NodeFactory<Integer>>() {} ) );
           }
       } );

NodeFactory<Integer> factory = injector.getInstance( Key.get( new TypeLiteral<NodeFactory<Integer>>() {} ) );

       System.out.println( "create a node first, create children later" );
       Node<Integer> node1 = factory.createNode( 0 );
       node1.createChildrenLater();
       System.out.println();

System.out.println( "create a node and create some children in its constructor" );
       Node<Integer> node2 = factory.createNode( 1 );
       node2.createChildrenLater();
   }


   public abstract static class Node<E> {

       public E value;

       public Node( E value ) {
           this.value = value;
       }

       public abstract void createChildrenLater();
   }

   public static interface NodeFactory<E> {

       Node<E> createNode( E value );

   }

   public static class IntegerNode extends Node<Integer> {

       private final NodeFactory<Integer> factory;

       @Inject
public IntegerNode( @Assisted Integer value, NodeFactory<Integer> factory ) {
           super( value );
System.out.println( "TestGuiceModule$IntegerNode.IntegerNode, value=" + value + ", factory identity=" + System.identityHashCode( factory ) );
           this.factory = factory;
           if ( value > 0 ) {
System.out.println( "creating children inside the node constructor" );
               Node<Integer> child = factory.createNode( value - 1 );
           }
       }

       @Override
       public void createChildrenLater() {
System.out.println( "TestGuiceModule$IntegerNode.createChildrenLater" );
           Node<Integer> child = factory.createNode( value - 1 );
       }

   }

}
--
You received this message because you are subscribed to the Google Groups 
"google-guice" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/google-guice?hl=en.

Reply via email to