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.