Computers have been my hobby since I was 12. Now I'm a freelance Java developer. Like many other developers I am working on various private projects. Some are open source components (Butterfly Components - DI container, web ui, persistence api, mock test api etc.). Some are the tutorials at tutorials.jenkov.com. Yet others are web projects. I hold a bachelor degree in computer science and a master degree in IT focused on P2P networks. Jakob has posted 35 posts at DZone. You can read more from them at their website. View Full User Profile

Butterfly DI Container v. 2.5-9-beta: Easier Collection, Array, and Map Configuration

09.10.2008
| 2969 views |
  • submit to reddit
Location: 
http://butterfly.jenkov.com

Butterfly Container is a Java dependency injection container. It is smaller (~100KB jar), yet more flexible and easier to use than Spring, Pico, and Guice (at least in the developers' opinion). Instead of XML, Butterfly Container is configured using a simple, flexible, Java-like configuration language, or by plugging plain non-annotation, non-reflection Java factories into the container. There are no external dependencies.

Here is an example of the script language:

object = * com.jenkov.MyObject();
myBean = * com.jenkov.MyBean(object);
myBean2 = * myBean.setExtraValue("someExtraValue");

The * means "new instance". A 1 would means "singleton". 

Though less important, Butterfly Container also has great performance. It is 2-4 times faster at instantiating objects than Guice. Since Guice claims to be faster than Spring, Butterfly Container is probably faster than Spring too.

Version 2.5.9-beta brings easy Collection, array, and Map configuration in the Butterfly Container Script language. Here are two examples:

myList = * ["value1", valueFromFactory2, com.jenkov.Value3() ];
myMap = *<"key1" : "value1", keyFromFactory2 : valueFromFactory2, com.jenkov.Key3() : com.jenkov.Value3() > ;

Version 2.5.9-beta also adds the ability to assign names to the input streams you read container scripts from. This name is used when an error is detected in the script, making it easier to find out what file the error ocurred in. It is now also possible to have the ScriptFactoryBuilder close the script input stream for you. This version also fixes a minor bug related to parsing and error messages.

0
Published at DZone with permission of its author, Jakob Jenkov.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Jakob Jenkov replied on Wed, 2008/09/10 - 7:07am

BTW the link to Butterfly Container is:

 http://butterfly.jenkov.com

Peter Veentjer replied on Thu, 2008/09/11 - 4:31am

I have a question about the Butterfly Container Script.

Is it an external or internal DSL? External DSL's are fixed and hard to customize. Often you need all kinds of special plugins (like custom written ANT tasks, or BeanFactories). But they can be very fast. Internal languages (for example something based on ruby or groovy) are much more flexibile (it is very easy to fall back on all the features of the 'parent' language).  So how easy is the language to extend? This is always an issue with DI containers. They feel kind of clumsy if you want something non standard.

Jakob Jenkov replied on Thu, 2008/09/11 - 5:52am

Hi Peter,

I think Butterfly Container Script is an external DSL, but since you can call any method, static or instance method, and reference any field, it is possible to extend the Butterfly Container Script with your own constants, functions and even instantiation modes or special-purpose factories. This is as easy as calling a method on any of your own classes. You just do it from inside a factory definition instead of in Java code. For instance, I have extended BCS to be able to inject thread local objects (e.g. a HttpServletRequest object or Connection object) in the web framework I am working on now and then. Here are a few simple examples:

myStaticFactory = * com.jenkov.StaticFactory().createInstance();
myObject1 = * myStaticFactory;

myFactory = 1 com.jenkov.VerySpecialFactory();
myObject2 = * myFactory.getTheNewInstance().setMoreValues("...");
myFunction = * com.jenkov.MyFunction.aStaticMethod($0);
myObject3 = * myFunction(com.jenkov.FunctionInput());


 

Extending the Butterfly Container Script is described in the three texts found here:

Extending BCS: Constants 
Extending BCS: Custom Functions
Extending BCS: Custom Instantiation Modes

Injecting ThreadLocal objects is described here:

Injecting ThreadLocal Objects

 

You can also just add a plain Java factory to the container if you need to do something you can't seem to squeeze into BCS (although I haven't yet encountered any such thing). You can access the Java factory from your scripts, and you can access script factories from your Java factories, as long as any referenced factory already exists in the container at the time the referencing factory is added.

Adding plain Java factories is briefly explained here:

Wrapping the Container in a JavaFactoryBuilder

Feel free to ask more questions...

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.