The easiest way to use Morph is to use the Morph static class. The main operations it supports are convert, copy, get and set. These methods allow you to: convert an object from one type to another, copy information from one object to another (already existing) object, retrieve (get) information from anywhere in an object graph and set information anywhere in an object graph, respectively.
The benefit of using the Morph static class directly is that it's simple, and you don't have to do any special setup. No matter what project you're working on, all you have to do is drop the morph JAR into your project's library directory and reference the Morph class. In addition, you are assured that no matter how the application you are working on is configured, Morph will work the way you're used to.
The drawback of using Morph in this way is that you cannot do any customization. The Morph class is a static facade that makes it easy to get started using Morph. To accomplish this goal, it hides all of the powerful customizations Morph provides. Fortunately, once you outgrow the capabilities that come with Morph out of the box, your own custom Morph configuration will live peacefully side by side with the Morph static class. Your existing code that utilizes the Morph static class will continue to work as it did before, and the parts of your application that require special configuration can have that special configuration limited to only those parts of the system that need the added complexity.
Morph.convert allows you to convert an object from one type to another. Here are some examples:
Integer three = new Integer(3); // code without Morph String string = new Integer(three); // or (without using Morph) string = "" + three; // code using Morph String string = Morph.convertToString(three); String three = "3"; // code without Morph Integer integer = new Integer(three); // code using Morph Integer integer = Morph.convertToIntegerObject(three); String three = "3"; // code without Morph int i= new Integer(three).intValue(); // or (without using Morph) int i = Integer.parseInt(3); // code using Morph int i = Morph.convertToInt(three);
Morph.copy allows information from one object to be copied to another object. The object to which information is copied may even be of a different type than the source object. A great example of when you need to do this type of thing is when you need the data in an HttpServletRequest to be available to lower tiers in your application but you don't want to tie your entire application to the servlet API. For example, let's say you are trying to get your data prepared for a method with a signature IServiceInterface.service(Map data):
// without Morph Map data = new HashMap(); for (Enumeration e=request.getParameterNames(); e.hasNext(); ) { String param = (String) e.next(); data.put(param, request.getParameter(param)); } // with Morph Map data = new HashMap(); Morph.copy(data, request); // actually with this particular example could also do Map data = (Map) Morph.convert(Map.class, request);
A common convention in Java programming is to write objects as JavaBeans and expose their configuration parameters as JavaBean properties. The Morph framework exposes all configuration options in this way. This allows Morph to be configured programmatically using simple syntax. An even more powerful way to configure Morph is to use a dependency injection framework such as Spring. (Dependency injection frameworks are also sometimes called Inversion of Control containers, or IoC containers). This will allow you to configure Morph using the same format you use to configure the rest of your application.
If you're completely lost at this point and wondering what the heck a dependency injection framework is, take a look here. Note that Morph uses Setter Injection rather than Constructor Injection. I (Matt Sgarlata) personally think dependency injection containers are the most significant innovation in computer programming since object orientation. If you don't know what dependency injection is, stop now and take a look at Spring, PicoContainer, or Hivemind! My favorite is Spring.
There is a whole lot of code in the Morph framework, but it all boils down to a few basic types of things: Transformers, Reflectors, Wrappers, Languages and Contexts. Each of these types of things is given its own package. We'll use the remainder of this section to briefly cover these types. For more information on a type, see the reference guide chapter about the type if one has been written. If you need more information or there is no reference chapter, see the JavaDoc documentation. Documentation can always be improved, but the documentation for each of the main interfaces is fairly complete.
Transformers transform data from one type to another. Transformers were essentially the inspiration for the entire framework, and they are targeted pretty squarely at the original goal for the framework, which was "to be able to convert anything to anything".
Reflectors were originally created to help implement Copiers, which are a type of Transformers. They provide a stateless model for accessing data from two main types of data structures: bean-like structures and container-like structures. It turns out reflectors are so useful, they can implement all sorts of neat functionality. If you have some type of special data type that you need Morph to understand, you probably want to write a Reflector. A good example of this is the DynaBeanReflector
Wrappers are very similar to reflectors, and in fact their APIs are nearly identical. The difference is that reflectors are stateless so that transformers can be implemented efficiently. Wrappers are more useful when you want to allow a method to take any type of bean-like or container-like data, but you don't want to have to overload the method for every conceivable bean (e.g. Object, Map) or container (e.g. Array, List)
Languages define a way to retrieve and modify arbitrary information in an object graph.
Contexts are similar to bean wrappers in that they provide stateful access to information stored in a bean-like object. Unlike beans, contexts are backed by the full power of a language, so they can be used to modify and change any information in an object graph. Also, the default context implementations provided with Morph implement the Map interface. This allows you to easily pass Contexts between tiers of an application, even if different tiers of the application are dependent on different APIs (e.g. the Servlet API in the presentation tier and the JDBC API in the resource tier).