Home > FAQ

Print
FAQ

Yan Container FAQ


What is Yan?

Yan container stands for Yet Another Non-intrusive container for object dependency injection.

It differs from all other container products in that it utilizes the combinator-oriented design.

Arbitrarily complex components can be constructed by declaratively combining simpler components, which may be combinations of yet simpler components.


Why do I need Yan?

Object dependencies may become unwieldy to manage for a big application using IOC design.

You may also want the ability to flexibly configure your IOC components.

Yan can help you there.


Yet another IOC container?

Yes.

We know that Pico Container and Spring Container are already very good containers. But Yan does offer some innovative features that we believe unique.


How do I use Yan?

Similar to Pico Container. Yan Container is a micro container that provides only Java API.

To create a container:

Container yan = new DefaultContainer();

To register a component using constructor:

yan.registerConstructor(A.class);

To register a component under a key:

yan..registerComponent("key1", comp);

To get an instance for a key:

yan.getInstance("key1");

To unregister a component under a key:

yan.unregisterComponent("key1");

XML support or scripting support can be built on top of this API though.


Which type of IOC do you support?

This question is hard to answer.

Simply put, we don't believe that there should be such thing called "IOC type".

If you meant whether we require you to expose a constructor or expose some java bean setters. No, we have no requirement at all.

You can use constructor (as in Pico), java bean (as in Spring), static method (as some people like me prefer), abstract factory, jndi, or even create your own bean convention ("giveXXX" rather than "setXXX"), any way that's most appropriate to your business object design.

Yan as an absolutely non-intrusive container does not attempt to tell you what is the right way to design your own application. It is an IOC container, not a code style checker.

In fact, if you can find some way of creating object that Yan has poor support, please kindly let us know. I'll jumpt to the computer and fix it.


How do I use static method injection?

Rather than saying Components.ctor(A.class), you do:

Components.static_method(A.class, "createInstance");

Hopefully it explains itself already.


How do I use non-static method injection?

Components.method(obj, "getName");

What if I don't have the 'obj' when assemblying components? What if another component 'x' is responsible for instantiating it?

Class Component has a 'method' function that does the job.

Component x = ...;
Component xname = x.method("getName");

xname is a Component that will call method "getName" against the instance created by component x.


How do I use the value of a component property?

"getName"?, why can't I just use the property name "name", "active" rather than "getName", "isActive"?

Yes. You can.

Function getter() is designed to handle Java Bean specification.

Component x = ...;
Component xname = x.getter("name");

xname is a Component that will call the getter of property "name" against the instance instantiated by component x.


How do I use the value of an indexed component property?

Very similar, provide your index number in the getter function.

Component x = ...;
Component xname = x.getter(0, "name");

xname is a Component that will retrieve the first element of indexed property "name" against the instance instantiated by component x.


How do I use the value of a nested component property?

What if the 'name' property is in an inner bean of class X? For example, X.account.name?

Just keep calling the getter function:

Component x = ...;
Component xname = x.getter("account").getter("name");

How is the singleton pattern supported?

a_component.singleton();

That's it.


How do I manual-wire a parameter?

How do I explicitly specify a value for a parameter?

You mean something like <property name="age"><value>15</value></property> in Spring?

Well, Yan's API reads very similar to that:

Components.bean(Person.class)
    .withProperty("age", Components.value(15));

How do I explicitly specify a constructor for a parameter?

Something like saying "for the 1st parameter, use the constructor of class A"?

Components.ctor(SomeClass.class)
    .withArgument(0, Components.ctor(A.class));

How do I disambiguate when more than one constructors are available?

Yan does not guess what you mean when ambiguity happens. You have to explicitly tell the container which constructor you want to call.

And that is easy:

Components.ctor(ClassWithMultipleConstructor.class, new Class[]{int.class});

The Class array parameter tells container which constructor you are planning to invoke.


How do I reference another component?

How do I do things similar to Spring "ref bean=xxx"?

Simple. Components.useKey() is what you need.

For example:

Components.useKey("xxx");

How do I make a bean property optional?

Although use of optional property is discouraged, because we believe it compromises predictability of the entire system, it is still supported.

Components.bean(A.class)
    .optionalProperty("salary");

This way, when the salary property cannot be resolved, it is silently skipped.


How do I use an alternative value if a component cannot be resolved?

some_component.option("my default value");

This tells the container to use "my default value" when some_component or any of its parts cannot be resolved.


How do I specify a default value for a bean property?

Components.bean(MyBeanClass.class)
    .withDefaultProperty("age", new Integer(-1));

This makes -1 the default value for age if age cannot be resolved.


How do I specify a default value for a parameter?

Similar to default property value, use withDefaultArgument function.

Components.ctor(SomeClass.class)
    .withDefaultArgument(1, new Integer(-1));

How is by-name resolution mode supported?

How do I achieve the "byName" mode that's available in Spring?

Although we are not sure if using the property name is a good way to resolve properties. We do provide a few alternative resolution policies, including the byName, through the jfun.yan.etc.Beans class.

By name:

Beans.byName(Components.bean(SomeBean.class));

By display name:

Beans.byDisplayName(Components.bean(SomeBean.class));

By fully qualified name (such as SomeBean.age):

Beans.byQualifiedName();

You can even customize your own policy by calling

Beans.resolveBy();

How do I set java bean properties for an object not created by a default constructor?

You mean things like this?

MyObj obj = MyObj.createInstance();//rather than new MyObj();
obj.setAge(1);
obj.setName("Tom");

Yes, you can do that too:

Components.bean(Components.static_method(MyObj.class, "createInstance"));

How do I make a singleton component gets new value for its properties every time it is requested?

My component A is singleton, yet I still want its properties set to a new instance every time A is requested.

Something like this?

A getA(){
  A result = getSingletonForA();
  result.setProperty1(new X());
  result.setProperty2(new Y());
  return result;
}

Simple. It is the bean instance that's singleton, not the properties.

So don't include the properties.

Make the component that creates the bean instance singleton instead.

Components.bean(Components.ctor(A.class).singleton());

No. I don't need to assign new instance to every property. Just one property needs to get new instance.

Alright. It is actually two steps:

First the bean instance is created as a singleton without setting this special property.

Secondly the special property gets set.

Component first_step = Components.bean(A.class)
    .ignoreProperty("specialProperty")
    .singleton(),
Component second_step = Components.bean(
    first_step,
    new String[]{"specialProperty"}
);

Using ignoreProperty(), we tell the bean to ignore the "specialProperty". And in the second step, we specially set the property for "specialProperty".


How do I turn off auto-wiring?

DefaultContainer honors auto-wiring. If you dislike it, we understand that. Use the ManualContainer class instead.

I want auto-wiring for my simple components, but not for a real complex one.

Use seal() to disable auto-wiring for a component.

Component not_auto_wired = component_a.seal();

The not_auto_wired component will not use auto-wiring.


How do I create private component that's only visible in a local scope?

My component A needs to use component B, but I don't want to register component B in the container. I want to keep it local and private to component A.

You only need to register a component into a container when you want it to be shared. If you want it only used by one component, here's what you can do:

yan.registerComponent("mycomp",
    Components.ctor(A.class).withArgument(0, Components.ctor(B.class))
);

The component for B is not registered in the container so invisible to other components, yet it can be used by component A.


How is component life-cycle supported?

How do I do stuff like "destroy-method=..., init-method=..."?

Lifecycle support is not built in to the container core. There's a separate lifecycle package that provides a simple lifecycle solution. This package supports what you wanted.

Component a = Components.ctor(A.class);
DefaultLifecycleManager manager = new DefaultLifecycleManager();
Component a_with_lifecycle = manager.newLifecycle()
  .initializer("init")
  .disposer("destroy")
  .manage(a);
//the a_with_lifecycle is a component with the desired life-cycle.

And this is the code to invoke lifecycle:

manager.init();
manager.dispose();

How is collection types such as List handled?

I need my component to create a java.util.List object, that List object should contain objects created from Component X and Component Y.

The Components.list() function can help you there.

Components.list(new Component[]{comp_x, comp_y})

This code tells container to collect the component instance from component x and component y and store them into a java.util.List object.


Can containers inherit each other?

How do I have one container "inherit" another container to form a container hierarchy?

Container hierarchy = container1.inherit(container2);

inherit is an immutable operation. It does not change the state of container1 or container2. Instead, the returned Container object maintains the inheritance hierarchy.

Using this hierarchy object, you can get the inheritance result that you want. (where components in container1 see those from container 2, but not vice versa)


Advanced component transformations.

For component X, I need to "ref" component Y. But instead of directly using component Y, I need to call y.getAccount() as the value of component X.

The jfun.yan.Map interface is what you need to implement in this case.

Don't panic. You are not going into the plumbing system of Yan container. All you need to do in the Map interface is to describe how you want to deal with the y object.

Example:

Components.useKey(`Y").map(new Map(){
    public Object map(Object y){
        return ((Y)y).getAccount();
    }
});

I have a component that should not be singleton. Yet, I do want to use the same instance created from that component for the first 2 parameters of component B.

Similar to the Java code:

B createB(){
    A a = new A();
    return new B(a, a, x, y);
}

Each time B is instantiated, a new instance of A should be created. But the first two parameters of B use the same new instance.

This is what you would do:

Component component_b = Components.useKey("componen_a").bind(
    new Binder(){
        public Creator bind(Object a){
            final Component tmp = Components.value(a);
            return Components.ctor(B).withArgument(0, tmp).withArgument(1, tmp);
    }
});

It involves a monadic combinator.

My apology if this is confusing you if you never heard of "monad" - a monster from the functional programming language castle.

Simply put, the bind function takes the result from component_a and use that value as the first and second parameter of class B's constructor.

Although the buzz word "monad" may sound intimidating, but the good news is: hey, you are still kept far away from the dirty dependency work. Yan Container runs silently under the hood.

And it is perfectly fine to not understand the "monad" concept. You just remember to describe your logic in the Binder.bind() function. That's it.

Powered by Atlassian Confluence