Getting started

Skip to end of metadata
Go to start of metadata

Overview

1. Include GeDA in your code

You can either include latest maven dependency of GeDA or simply download jar files manually (see home page links) and add them to class path (with manual install you'll have to manage dependencies of byte code generation and logging on your own - just examine POM but in most cases you'll get away with javassist and slf4j - chances are you already have those).

There are three working modules:

core - is the actual bare generic DTO assembler (this module is mandatory)

spring-integration - is integration with Spring 3.x.x (this module is recommended if you are using Spring framework)

osgi - OSGi bundle with OSGi service to provide full support to GeDA core. A genuine OSGi bundle (not just another OSGi-fied library)

One examples module:

examples - here we try to provide end to end examples of how GeDA may be used (there is also lots of examples in the JUnit test of each module)

Three additional testing modules:

core-ptest - tests GeDA behaviour and performance using multithreading

core-btest - test for GeDA benchmark on performance (please help us keep this up to date and send feedback if you think other libraries should be benchmarked)

osgi-itest - PAX exam for OSGi bundle

2. [option1] Annotate your DTO objects

GeDA offers a lot of options on this but there are some rules on how to use annotations provided.

@Dto - this annotation is a mandatory marker for all GeDA enabled DTO classes (this is not strictly speaking necessary for GeDA but it provides you with more control over what classes GeDA should "understand"). It also provides means for autobinding when you have a one-to-one relationship between DTO and Entities.

@DtoField - simple annotation placed on a field to indicate that it will accept and/or provide basic java data (i.e. immutable basic java types such as primitives, wrappers, String etc) or DTO object if dtoBeanKey is specified.

@DtoParent - this is a complementing annotation to @DtoField to indicate a field that is actually a relation dependency DTO. The easiest way to think of it is relational entity - in most cases you only want to update the linking ID and this annotation allows GeDA to understand that.

@DtoCollection - allows complex collections synchronisation for collection of object. Please refer to detailed guide on some peculiarities around this.

@DtoMap - allows complex map synchronisation in a similar way as @DtoCollection but also allowing you to specify keys.

@DtoVirtualField - this one allows you to have full control over your DTO and derive data for field on your DTO even if no such field exist on the Entities

There are lots of examples of these mappings in the core's JUnit tests in the com.inspiresoftware.lib.dto.geda.assembler.examples package

2. [option2] Use DSL to create your mappings

Since v. 2.1.0 GeDA offers a DSL registry interface with DefaultDSLRegistry default implementation that allows you to do everything that you were able to do with annotations using DSL.

Use the dto(?).forEntity(?) to establish class to class mapping and then invoke withField, withCollection and withMap methods for fields that would otherwise had annotations on them.

3. Create Bean Factory (optional)

If you want to extract complex object graphs and let GeDA synchronize some of the objects instantiation you will need to implement BeanFactory. It has only one method "Object #get(String key)" which allows GeDA to instantiate classes if you follow IoC principles. The key used would be key you specify for dtoBeanKey and entityBeanKeys in your annotations.

Architecture of GeDA follows SOLID principles. The responsibility of Assembler instance is to assemble - not to create instances - that is why GeDA library has BeanFactory API.
GeDA core provides only interfaces for BeanFactory and ExtensibleBeanFactory. The implementations are in most cases project specific and influence performance a lot. Hence it was architectural decision to leave those out. However there are default implementations in spring-integration (DTOFactoryImpl) and osgi (OSGiBundleDTOFactoryImpl) modules. You can use those for reference if you use GeDA core only.

4. Register value adapters (optional)

If your Entity-DTO relationship is complex and does not just involve copying values from one java bean to another - then you will probably need value converters. You would use them if:

  • you have @DtoVirtualField
  • you have non matching data types in your fields (say boolean and enum (YES, NO))

To implement a converter you need to implement ValueConverter interface that has two methods #convertToDto and #convertToEntity.

If you are using @DtoParent annotation you will need to have EntityRetriever adapter that is pretty much just one method #retrieveByPrimaryKey which you specify in your annotations.

Lastly if you are using @DtoCollection and @DtoMap you will need to implement DtoToEntityMatcher with just one method #match to allow GeDA understand how to synchronize objects in collections and maps.

All of the above are Adapter instances that can be bundled (but do not have to) into a AdaptersRepository.

It is advisable that you do use this repository to minimise number of instances of the Adapters in your system. When assembly time comes you can use repo.getAll() to get them.
It is very important to keep all adapters stateless (and hence thread-safe!)

 
 

5. Finally - some code.

Once you have completed the necessary steps for your particular case - basic snippet for assembly will look like this:

...

// get all adapters
final Map<String, Object> adapters = adaptersRepo.getAll();


// [option 1] get assembler instance from cache or create new using annotated dto class
final Assembler asm = DTOAssembler.newAssembler(dto.getClass(), entity.getClass());


// OR [option 2] do the same for the DSL approach that does not require dto class to be annotated
final Assembler asm = DTOAssembler.newAssembler(dto.getClass(), entity.getClass(), registry);
...


asm.assembleDto(dto, entity, adapters, beanFactory);

...

asm.assembleEntity(dto, entity, adapters, beanFactory);

...
GeDA caches assembler instances internally so you do not need to keep internal references. Call to DTOAssembler.new will check if appropriate instance already exists prior attempting to create a new one.

Learn by Example

We strongly recommend reviewing all examples as some of them contain interesting combinations that may be useful.
See this article about setting up GeDA project

The overal API is quite simple as could be seen in step 5 above. The complexity comes from how you use the anootations or DSL and combines them together to achive maximum performance from your DTOs.

Unfortunately covering every single case is a thankless task as each case would be very specific. Below you will find some basic use cases for different mappings. However we strongly encourage checking out the source code as we have a huge section with many working examples showing how simple, complex, collections, recursive, generics mapping work (See last section More examples to see where those are in source code).

Simple field mapping

Field Annotations

Mapping TestDto2Class to an arbitrary entity
@Dto
public class TestDto2Class {

	@DtoField("entityId")
	private Long myLong; // maps dto.myLong to entity.entityId
	@DtoField(value = "name", readOnly = true)
	private String myString;  // maps dto.myString to entity.name in read only mode
	@DtoField("number")
	private Double myDouble; // maps dto.myDouble to entity.number
	@DtoField("subentity.decision", converter = "boolToEnum")
	private Boolean myBoolean; // maps dto.myBoolean to entity.subentity.decision using converter

...getters/setter go here...

}

Field DSL

This example uses the same DTO POJO's as annotations version but without the need for the annotations on classes
Mapping TestDto2Class to an arbitrary entity
final ExtensibleBeanFactory bf = ...;

final Registry registry = new DefaultDSLRegistry(bf);

registry
   // main mapping of TestDto2Class to a generic entity that has the below mentioned properties
   // "TestDto2Class" - is a key in BeanFactory
   .dto("TestDto2Class").forEntityGeneric()
   // maps dto.myLong to entity.entityId in read only mode
   .withField("myLong").forField("entityId").readOnly()
   // maps dto.myString to entity.name
   .and()
   .withField("myString").forField("name")
   // maps dto.myDouble to entity.number
   .and()
   .withField("myDouble").forField("number")
   // maps dto.myBoolean to entity.subentity.decision using converter
   .and()
   .withField("myBoolean").forField("subentity.decision").converter("boolToEnum");

Mapping TestDto2Class to an specific entity TestEntity2Class
final ExtensibleBeanFactory bf = ...;

final Registry registry = new DefaultDSLRegistry(bf);

registry
   // main mapping of TestDto2Class to a generic entity that has the below mentioned properties
   // "TestDto2Class" and "TestEntity2Class" - are keys in BeanFactory
   .dto("TestDto2Class").forEntity("TestEntity2Class")
   // maps dto.myLong to entity.entityId
   .withField("myLong").forField("entityId")
...

Mapping TestDto2Class to an specific entity TestEntity2Class using class
final ExtensibleBeanFactory bf = ...;

final Registry registry = new DefaultDSLRegistry(bf);

registry
  // main mapping of TestDto2Class to a generic entity that has the below mentioned properties
  // TestDto2Class and TestEntity2Class - are actual classes (Entity can be an interface as well)
  // alias("TestDto2Class") registers TestDto2Class.class with key "TestDto2Class" in BeanFactory
  .dto(TestDto2Class.class).alias("TestDto2Class").forEntity(TestEntity2Class.class)
  // maps dto.myLong to entity.entityId
  .withField("myLong").forField("entityId")
  // maps dto.myString to entity.name
...

Collection field mapping

Collections Annotations

Mapping TestDto7CollectionClass that holds collection of TestDto7CollectionSubInterface elements to an arbitrary entity
/** DTO that holds collection of other DTOs */
@Dto
@Ignore
public class TestDto7CollectionClass {

    @DtoCollection(
	// name of the collection field
        value = "collection",
	// Bean key for BeanFactory to create new entity beans during synchronisation
        entityBeanKeys = "com.inspiresoftware.lib.dto.geda.assembler.TestEntity7CollectionSubClass",
	// Bean key for BeanFactory to create new instances of DTO for collection elements
        dtoBeanKey = "com.inspiresoftware.lib.dto.geda.assembler.TestDto7CollectionSubClass",
	// Matcher that allows to aid synchronisation process
        dtoToEntityMatcher = Test7Matcher.class,
	// Generic collection element class (ideally should be an interface)
        entityGenericType = TestEntity7CollectionSubClass.class
    )
    private java.util.Collection<TestDto7CollectionSubInterface> nestedString;

... getters/setters go here ...

}

/** DTO that describes collection item. */

@Dto
@Ignore
public class TestDto7CollectionSubClass implements TestDto7CollectionSubInterface {

    // default mapping to entity property with same name
    @DtoField
    private String name;

... getters/setters go here ...

}

/** Matcher for the above entities. */
public class Test7Matcher implements DtoToEntityMatcher<TestDto7CollectionSubClass, TestEntity7CollectionSubClass> {

    public boolean match(final TestDto7CollectionSubClass testDto7CollectionSubClass,
    		final TestEntity7CollectionSubClass testEntity7CollectionSubClass) {
        final String dtoName = testDto7CollectionSubClass.getName();
        final String entityName = testEntity7CollectionSubClass.getName();

        return dtoName != null && entityName != null && dtoName.equals(entityName);
    }
}


Collections DSL

This example uses the same DTO POJO's as annotations version but without the need for the annotations on classes
Mapping TestDto7CollectionClass that holds collection of TestDto7CollectionSubInterface elements to an arbitrary entity
final ExtensibleBeanFactory bf = ...;

final Registry registry = new DefaultDSLRegistry(bf);

registry
        // main mapping
        .dto(TestDto7CollectionClass.class).forEntity("com.inspiresoftware.lib.dto.geda.assembler.TestEntity7CollectionSubClass")
        // map collection field
	.withCollection("nestedString").forField("collection")
	// Bean key for BeanFactory to create new instances of DTO for collection elements
        .dtoBeanKey("com.inspiresoftware.lib.dto.geda.assembler.TestDto7CollectionSubClass")
	// Bean key for BeanFactory to create new entity beans during synchronisation
        .entityBeanKeys("com.inspiresoftware.lib.dto.geda.assembler.TestEntity7CollectionSubClass")
	// Matcher that allows to aid synchronisation process
        .dtoToEntityMatcherKey(Test7Matcher.class)
	// NO NEED to specify entityGenericType - since this is all runtime

registry
        // item mapping
        .dto(TestDto7CollectionSubClass.class).forEntityGeneric()
        // default mapping to entity property with same name
        .withField("name")


Map field mapping

Maps Annotations

Maps Example 1: Mapping TestDto12MapToCollectionClass map property from a collection on entity TestEntity12CollectionItemInterface
@Dto
@Ignore
public class TestDto12MapToCollectionClass implements TestDto12MapIterface {

	@DtoMap(
	     // map this DTO property to a nested entity property
	     value = "collectionWrapper.items",
	     // bean key for new DTO objects
	     dtoBeanKey = "dtoItem",
	     // entity bean keys - need two because we have two levels "collectionWrapper" then "items"
	     entityBeanKeys = { "nestedEntity", "entityItem" },
	     // matcher to be used for synchronisation
	     dtoToEntityMatcher = Test12KeyMapToEntityMatcher.class,
	     // generic interface for item entity
	     entityGenericType = TestEntity12CollectionItemInterface.class,
	     // default collection class for creating new collection on entity
	     entityMapOrCollectionClass = ArrayList.class,
	     // property that will be used on collection element as
	     // key (i.e. Map.Entry[items[i].name = items[i]])
	     entityCollectionMapKey = "name")
	private Map<String, TestDto12CollectionItemIterface> items;

... getters/setters go here ...

}

...mapping for item follow...

/** Matcher for the above entities. */
public class Test12KeyMapToEntityMatcher implements
        DtoToEntityMatcher<String, TestEntity12CollectionItemInterface> {

    public boolean match(final String dtoKey,
    		final TestEntity12CollectionItemInterface entity) {
        final String dtoName = dtoKey;
        final String entityName = entity.getName();

        return dtoName != null && entityName != null && dtoName.equals(entityName);
    }
}
Maps Example 2: Mapping TestDto12MapToMapByKeyClass map property from a map on entity TestEntity12CollectionItemInterface and use value for DTO
@Dto
@Ignore
public class TestDto12MapToMapClass implements TestDto12MapIterface {

	@DtoMap(
	     // map DTO map property to an entity collection property
	     value = "items",
	     // bean key for new DTO objects
	     dtoBeanKey = "dtoItem",
	     // entity bean key
	     entityBeanKeys = "entityItem",
	     // matcher to be used for synchronisation
	     dtoToEntityMatcher = Test12MapKeysMatcher.class,
	     // generic interface for item entity
	     entityGenericType = TestEntity12CollectionItemInterface.class)
	private Map<String, TestDto12CollectionItemIterface> items;

... getters/setters go here ...

}

...mapping for item follow...

/** Matcher for the above entities. */
public class Test12MapKeysMatcher implements DtoToEntityMatcher<String, String> {

    public boolean match(final String dtoKey,
    		final String entityKey) {
        final String dtoName = dtoKey;
        final String entityName = entityKey;

        return dtoName != null && entityName != null && dtoName.equals(entityName);
    }
}

Maps Example 3: Mapping TestDto12MapToMapByKeyClass map property from a map on entity TestEntity12CollectionItemInterface and use key for DTO
@Dto
@Ignore
public class TestDto12MapToMapByKeyClass implements TestDto12MapByKeyIterface {

	@DtoMap(
	     // map DTO map property to an entity collection property
	     value = "items",
	     // bean key for new DTO objects
	     dtoBeanKey = "dtoItem",
	     // entity bean key
	     entityBeanKeys = "entityItem",
	     // matcher to be used for synchronisation
	     dtoToEntityMatcher = Test12MapEntityByKeyMatcher.class,
	     // generic interface for item entity
	     entityGenericType = TestEntity12CollectionItemInterface.class,
	     // entity's map entry key should be used for conversion rather
	     // than value (i.e. Map.Entry[items[i].key = items[i].value])
	     useEntityMapKey = true)
	private Map<TestDto12CollectionItemIterface, String> items;


... getters/setters go here ...

}

...mapping for item follow...

/** Matcher for the above entities. */
public class Test12MapEntityByKeyMatcher implements
       DtoToEntityMatcher<TestDto12CollectionItemIterface, TestEntity12CollectionItemInterface> {

    public boolean match(final TestDto12CollectionItemIterface dto,
    		final TestEntity12CollectionItemInterface entity) {
        final String dtoName = dto.getName();
        final String entityName = entity.getName();

        return dtoName != null && entityName != null && dtoName.equals(entityName);
    }
}

Maps DSL

This example uses the same DTO POJO's as annotations version but without the need for the annotations on classes
Maps Example 1: Mapping TestDto12MapToCollectionClass map property from a collection on entity TestEntity12CollectionItemInterface
final ExtensibleBeanFactory bf = ...;
final Registry registry = new DefaultDSLRegistry(bf);
registry
        // main mapping
        .dto(TestDto12MapToCollectionClass.class).forEntityGeneric()
        // map this DTO property to a nested entity property
        .withMap("items").forField("collectionWrapper.items")
        // bean key for new DTO objects
        .dtoBeanKey("dtoItem")
        // entity bean keys - need two because we have two levels "collectionWrapper" then "items"
        .entityBeanKeys("nestedEntity", "entityItem")
        // matcher to be used for synchronisation
        .dtoToEntityMatcherKey(Test12KeyMapToEntityMatcher.class)
        // default collection class for creating new collection on entity
        .entityMapOrCollectionClass(ArrayList.class)
        // property that will be used on collection element as key (i.e. Map.Entry[items[i].name = items[i]])
        .entityCollectionMapKey("name")
        // NO NEED to specify entityGenericType - since this is all runtime


registry
        // item mapping
        .dto(TestDto12MapToCollectionClass.class).forEntityGeneric()
...mapping for item follow...

Maps Example 2: Mapping TestDto12MapToMapByKeyClass map property from a map on entity TestEntity12CollectionItemInterface and use value for DTO
final ExtensibleBeanFactory bf = ...;
final Registry registry = new DefaultDSLRegistry(bf);
registry
        // main mapping
        .dto(TestDto12MapToMapClass.class).forEntityGeneric()
        // map this DTO property to entity property with same name
        .withMap("items")
        // bean key for new DTO objects
        .dtoBeanKey("dtoItem")
        // entity bean key
        .entityBeanKeys("entityItem")
        // matcher to be used for synchronisation
        .dtoToEntityMatcherKey(Test12MapKeysMatcher.class)
        // NO NEED to specify entityGenericType - since this is all runtime

registry
        // item mapping
        .dto("dtoItem").forEntityGeneric()
...mapping for item follow...

Maps Example 3: Mapping TestDto12MapToMapByKeyClass map property from a map on entity TestEntity12CollectionItemInterface and use key for DTO
final ExtensibleBeanFactory bf = ...;
final Registry registry = new DefaultDSLRegistry(bf);
registry
        // main mapping
        .dto(TestDto12MapToMapByKeyClass.class).forEntityGeneric()
        // map this DTO property to entity property with same name
        .withMap("items")
        // bean key for new DTO objects
        .dtoBeanKey("dtoItem")
        // entity bean key
        .entityBeanKeys("entityItem")
        // matcher to be used for synchronisation
        .dtoToEntityMatcherKey(Test12MapEntityByKeyMatcher.class)
        // entity's map entry key should be used for conversion rather than value
        .useEntityMapKey();
        // NO NEED to specify entityGenericType - since this is all runtime


registry
        // item mapping
        .dto("dtoItem").forEntityGeneric()
...mapping for item follow...

Parent entities

Some entities are not purely writable. E.g. if we are working with database relations and we do not want to re-create Parent entity but have a way to retrieve it and set by primary key. This is the purpose of Parent annotation / DSL.

Parent Annotations

Mapping TestDto11ChildClass property "parent" to a TestDto11ParentInterface, so that we do not create a blank instance but retrieve this parent object
@Dto
@Ignore
public class TestDto11ChildClass implements TestDto11ChildInterface {

	@DtoParent(
			// Defines the primary key to use to retrieve TestDto11ParentClass i.e. parent.getParentId()
			value = "parentId",
			// Adapter key which will be used to retrieve this entity
			// HibernateGet.retrieveByPrimaryKey(TestDto11ParentInterface.class, TestDto11ParentClass.class, parent.getParentId())
			retriever = "HibernateGet"
			)
	@DtoField(
			// Property that defines getter for this field
			value = "parent",
			// Bean key that will be used for creating instances of TestDto11ParentInterface
			dtoBeanKey = "TestDto11ParentClass",
			// Bean key that will be used for creating instances of TestEntity11ParentClass
			entityBeanKeys = "TestEntity11ParentClass"
			)
	private TestDto11ParentInterface parent;

... getters/setters go here ...

}

public class HibernateGet implements ExposedEntityRetriever {

    private Session session;

	public HibernateGet(Session session) {
		this.session = session;
	}

    public Object retrieveByPrimaryKey(final Class entityInterface,
                                       final Class entityClass,
                                       final Object primaryKey) {
        return session.get(entityClass, primaryKey);
    }

}

Parent DSL

This example uses the same DTO POJO's as annotations version but without the need for the annotations on classes
Mapping TestDto11ChildClass property "parent" to a TestDto11ParentInterface, so that we do not create a blank instance but retrieve this parent object
final ExtensibleBeanFactory bf = ...;

final Registry registry = new DefaultDSLRegistry(bf);

registry
        // main mapping
        .dto(TestDto11ChildClass.class).forEntityGeneric()
        // Property that defines getter for this field
        .withField("parent")
            // Bean key that will be used for creating instances of TestDto11ParentInterface
            .dtoBeanKey("TestDto11ParentClass")
            // Bean key that will be used for creating instances of TestEntity11ParentClass
            .entityBeanKeys("TestEntity11ParentClass")
            // Defines the primary key to use to retrieve TestDto11ParentClass i.e. parent.getParentId()
            .dtoParent("parentId")
            // HibernateGet.retrieveByPrimaryKey(TestDto11ParentInterface.class, TestDto11ParentClass.class, parent.getParentId())
            .retriever("HibernateGet")
registry
        // parent mapping
        .dto(TestDto11ParentClass.class).alias("TestEntity11ParentClass").forEntityGeneric()
...mapping for parent follow...

Sub Entities

Sub entities are simply fields that represent DTO's, so we need to create on-the-fly sub assemblers to transfer data. This is easily accomplished by providing dtoBeanKey and entityBeanKeys to DtoField annotation / withField() DSL.

Sub Entities Annotations

Mapping TestDto11Class property "sub" to a TestEntity11SubClass in "chained.subentity"
@Dto
@Ignore
public class TestDto11Class implements TestDto11Interface {

	@DtoField(
			// map property for this field
			value = "chained.subentity",
			// Bean key that will be used for creating instances of TestDto11SubInterface
			dtoBeanKey = "TestDto11SubClass",
			// Bean keys that will be used for creating instances of TestEntity11ChainSubClass and TestEntity11SubClass
			entityBeanKeys = { "TestEntity11ChainSubClass", "TestEntity11SubClass" }
			)
	private TestDto11SubInterface sub;

... getters/setters go here ...

}

Sub Entities DSL

This example uses the same DTO POJO's as annotations version but without the need for the annotations on classes
Mapping TestDto11Class property "sub" to a TestEntity11SubClass in "chained.subentity"
final ExtensibleBeanFactory bf = ...;

final Registry registry = new DefaultDSLRegistry(bf);

registry
        // main mapping
        .dto(TestDto11Class.class).forEntityGeneric()
        // map property for this field
        .withField("sub").forField("chained.subentity")
            // Bean key that will be used for creating instances of TestDto11SubInterface
            .dtoBeanKey("TestDto11SubClass")
            // Bean key that will be used for creating instances of TestEntity11ChainSubClass and TestEntity11SubClass
            .entityBeanKeys("TestEntity11ChainSubClass", "TestEntity11SubClass")
...mapping for parent follow...

Virtual fields

Virtual field allow to process incompatible or inexistent fields and map them to dto. The rationale is that some fields values must be computed from two or more other field on the source entity and hence no clear mapping for entity field can be defined. Therefore GeDA provides virtual field mapping to account for this.

Virtual fields Annotations

Mapping TestDto20Class virtual field
@Dto
@Ignore
public class TestDto20Class {

	@DtoVirtualField(converter = "VirtualMyBoolean")
	private Boolean myBoolean;

... getters/setters go here ...

}

public class VirtualMyBooleanConverter implements ValueConverter {

       public static final ThreadLocal userThreadLocal = new ThreadLocal();


	/** {@inheritDoc} */
	public Object convertToDto(final Object object, final BeanFactory beanFactory) {
		final TestEntity20Class entity = (TestEntity20Class) object;
		return entity.whatWasComplexDecision(userThreadLocal.get());
	}

	/** {@inheritDoc} */
	public Object convertToEntity(final Object object, final Object oldEntity,
			final BeanFactory beanFactory) {
		final TestEntity20Class entity = (TestEntity20Class) oldEntity;
		entity.makeComplexDecision((Boolean) object, userThreadLocal.get());
		return entity;
	}

}

Virtual fields DSL

Mapping TestDto20Class virtual field
final ExtensibleBeanFactory bf = ...;

final Registry registry = new DefaultDSLRegistry(bf);

registry
        // main mapping
        .dto(TestDto20Class.class).forEntityGeneric()
        // map property for this field
        .withField("myBoolean").forVirtual().converter("VirtualMyBoolean")

Beyond entities (Maps and Lists)

From time to time it is necessary to work with Lists and Maps instead of objects themselves. For example consider the following scenario: We have an application supported by Hibernate ORM but we also use Full text search capabilities backed by Lucene. Hibernate search allows to wrap that and get the entities - but we do not want that. We do not want to hit the database unless we are really sure we get the right result from search. So we use projectsion which return as Map<String,Object>. We still want to use the same fields names but apply it to map. No fear - GeDA is here...

Beyond entities Annotations

Mapping TestDto2Class and use it for entities, maps and lists
/* Basic mapping */
@Dto
@Ignore
public class TestDto2Class {

	@DtoField("name")
	private String myString;

... getters/setters go here ...

}

Using assembler for entity
final TestEntity2Class entity = ...;
final TestDto2Class dto = new TestDto2Class();
final Assembler assembler =
	DTOAssembler.newCustomAssembler(TestDto2Class.class, TestEntity2Class.class);
// assemble DTO from entity
assembler.assembleDto(dto, entity, null, null);
final TestEntity2Class copy = new TestEntity2Class();
// assemble Entity from Dto
assembler.assembleEntity(dto, copy, null, null);

Okay - what about Map?

Using assembler for map
final Map<String, Object> map = new HashMap<String, Object>;
map.put("name", "My name is HashMap");
final TestDto2Class dtoFromMap = new TestDto2Class();
final Assembler assembler =
	DTOAssembler.newCustomAssembler(TestDto2Class.class, Map.class);
// assemble DTO from map
assembler.assembleDto(dtoFromMap, map, null, null);
final Map<String, Object> mapCopy = new HashMap<String, Object>;
// assemble Map from Dto
assembler.assembleEntity(dtoFromMap, mapCopy, null, null);

Was it cool or what? All we needed to change the target entity class

Okay - what about List?

Using assembler for list
final List<Object> list = new ArrayList<Object>;
list.add("name");
list.add("My name is ArrayList");
final TestDto2Class dtoFromList = new TestDto2Class();
final Assembler assembler =
	DTOAssembler.newCustomAssembler(TestDto2Class.class, Map.class);
// assemble DTO from List
assembler.assembleDto(dtoFromList, list, null, null);
final List<Object> listCopy = new ArrayList<Object>();
// assemble List from Dto
assembler.assembleEntity(dtoFromList, listCopy, null, null);

Again - pure awesomeness

But this is just to get you started - how about joggling between assemblers?

DTO mayhem
final TestEntity2Class entity = ...;
final TestDto2Class dto = new TestDto2Class();
final Assembler entityAsm =
	DTOAssembler.newCustomAssembler(TestDto2Class.class, TestEntity2Class.class);
final Assembler mapAsm =
	DTOAssembler.newCustomAssembler(TestDto2Class.class, Map.class);

// assemble DTO from entity to get data
entityAsm.assembleDto(dto, entity, null, null);

// assemble Map from Dto
final Map<String, Object> mapObj = new HashMap<String, Object>();
mapAsm.assembleEntity(dto, map, null, null);

... do something with map like pass to lucene or auto generate web form ...

// get values from map to DTO
mapAsm.assembleDto(dto, map, null, null);

// put DTO value to original entity
entityAsm.assembleEntity(dto, entity, null, null);

Beyond entities DSL

DSL works much in the same way as the Assembler interface is the same for all types of assemblers. However there are subtle differences in how DSL works. Annotations are static so in fact all @Dto annotations are equivalent to registry.dto("someDto").forEntityGeneric(). Meaning that we map to an arbitrary entity and hence with annotations we can only have one mapping per DTO class. This is inflexible when for example we will full read/write access to fields for DTO/Entity mapping but read only access for DTO/Map. So here are some techniques for working with DSL.

Simple Alternative Mappings
// We define SomeDto to SomeEntity mapping with single field "field1"
// This mapping work only for this pair
registry.dto(SomeDto.class).forEntity(SomeEntity.class).withField("field1");

// Define SomeDto to HashMap with read only access for field1 only
registry.dto(SomeDto.class).forEntity(HashMap.class).withField("field1").readOnly();

// Finally define SomeDto to generic entity mapping (a sort of catch all) with uses
// converter for firld1
registry.dto(SomeDto.class).forEntityGeneric().withField("field1").converter("field1Converter");

As you can see with DSL we can provide alternative mappings to fine grain how exactly entities are mapped.

But this looks like duplication? Is there a way to overcome this? Yes, of course!

Suppose SomeEntity has subclass SomeComplexEntity - how can we reuse mappings from SomeEntity?

Reuse mappings
// we define single field mapping
registry.dto(SomeDto.class).forEntity(SomeEntity.class).withField("field1");

// useContextFor allows to copy all mappings from SomeDto-SomeEntity pair to SomeDto-SomeComplexEntity
// and then we add another mapping to it for field2.
registry.dto(SomeDto.class)
       .useContextFor(dtoCtx.forEntity(SomeEntity.class), SomeComplexEntity.class).withField("field2");

When using useContextFor we are copying mappings as they are at this point in time. So we get a copy of mappings and apply it to SomeComplexEntity. The original mappings remain unchanged. So two graphs of mapping will exist in isolation.

More examples

We do appreciate that there are quite a few configurations involved in mapping DTO however it would be impractical to try an explain all use cases for each feature of GeDA API.

Please download source code and have a look at our comprehensive list of examples. It will be much easier for you to understand how GeDA works by looking at actual working examples.

The examples are located in two places: 

examples module



And some more advanced and not so easy to read core examples used by JUnits

The example are located in core/src/test/java/com.inspiresoftware.lib.dto.geda.assembler.examples package:



We strongly recommend to setup GeDA project in an IDE such as Intellij IDEA or Eclipse as you will be able to easily navigate to the JUnit test that use the sample mapping DTO and Entity files
See this article about setting up GeDA project

All example DTO and Entities are used in one or more JUnit tests or in a dedicated examples module that clearly show the use cases for each feature of GeDA.

examples and performance testing modules (core-btest, core-ptest and osgi-itest) are not meant to be used as dependencies to your project. Please use them only as sandbox to test out some of GeDA's features by setting up GeDA project

Got stuck?

Post your question on GeDA Google Groups

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.