Skip to content
Ramiro Serrato edited this page May 16, 2017 · 18 revisions

Maker

Welcome to the Maker wiki!


The idea behind this project comes from a real problem that I faced in one of my previous jobs. The requirements were basically two.

  1. We could not use any framework that required runtime configuration, for example Spring or Guice. The architects of the project wanted something light, which wouldn't require heavy startup cycles that could make the system to fail during initialization and which are hard to test and debug for failures.

  2. The framework to be used should allow us to define dependencies to be injected, those definitions could come from libraries that would be distributed as jars, but with the ability to override those dependencies if needed by the application importing those libraries, in addition to that the dependencies could be overridden lets say by jar2 which uses jar1 as library but jar3 that uses jar1 as well could have its own redefinition of the dependency, a practical example is jdbc drivers and url definition, jar1 can have a definition of a datasource that is used inside its own code, but jar2 needs a different database or driver, the same for jar3. Without having to rewire their dependencies individually, we have a single pointer for datasource which is wired throughout the dependency context, but with different values that are overridden on demand.

The idea is to use the static nature of enums to fire the injection of dependencies and provide a model that allow us to create Singleton and Prototype dependencies. I took some ideas of the concepts of IoC and DI from Spring, having the way of declaratively/programmatically define DI/IoC contexts that allows us to wire beans and any kind of Java objects without requiring many external dependencies.

The pattern for defining dependencies is:

Pattern: NAME (isSingleton) { makeInstance() { <object creation logic > } }

Example, the LivingBeingMaker. Definition of the Maker context objects.

        SPARKY_DOG (true) {
		@Override
		public Dog makeInstance(Properties properties) {
			Dog sparky = new Dog();
			sparky.setName("Sparky");
			return sparky;
		}
	},

	PINKY_DOG (true) {
		@Override
		public Dog makeInstance(Properties properties) {
			Dog pinky = new Dog();
			pinky.setName("Pinky");
			return pinky;
		}
	},

In the above code we see how two injection definitions are declared, both are instances of the class Dog and are singleton as determined by the "true" argument value, the framework makes sure that the same instance is always returned.

The framework is very flexible as you define the instance creation programmatically, you can wire objects within the maker context or outside of it, here is an example of a third object that wires the previously defined instances.

        SPARKY_FAMILY (true) {  // A wired object
		@Override
		public DogFamily makeInstance(Properties properties) {
			DogFamily dogFamily = new DogFamily();
			dogFamily.setParent1(LivingBeingMaker.<Dog>get(SPARKY_DOG));
			dogFamily.setParent2(LivingBeingMaker.<Dog>get(PINKY_DOG));
			return dogFamily;
		}
	},

We can define Prototype objects, which means that every time the injection is performed it will return a new instance of the class. For that we need to pass a "false" as argument.

        SIAMESE (false)  { @Override public Cat makeInstance(Properties properties) { return new Cat(); } },
	LABRADOR (false) { @Override public Dog makeInstance(Properties properties) { return new Dog(); } },

You may want to ask what is that Properties argument in the makeInstance method. It is used for passing configuration properties to the instance creation (singleton or prototype), but this properties cannot be defined when injecting the dependencies at runtime, they are statically resolved when initializing the Maker context. This is useful for passing environment based configuration. E.g. database url and credentials that could be different from dev, qa, prod environments and we want to set from a properties file or other source.

        DAISY (false) { 
		@Override	
		public Plant makeInstance(Properties properties) {	
			Daisy daisy = new Daisy();
			daisy.setKind(properties.getProperty("daisy_kind"));
			return daisy;	
		}
	},
	
	CEIBA (false) { 
		@Override 
		public Plant makeInstance(Properties properties) { 
			Ceiba ceiba = new Ceiba();
			ceiba.setAge(new Integer(properties.getProperty("ceiba_age")));
			return ceiba;	
		}
	};
Clone this wiki locally