/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.util.fudgemsg; import static org.fudgemsg.mapping.FudgeSerializer.addClassHeader; import java.util.List; import java.util.Map; import java.util.Set; import org.fudgemsg.FudgeField; import org.fudgemsg.FudgeMsg; import org.fudgemsg.FudgeRuntimeException; import org.fudgemsg.MutableFudgeMsg; import org.fudgemsg.mapping.FudgeBuilder; import org.fudgemsg.mapping.FudgeDeserializer; import org.fudgemsg.mapping.FudgeSerializer; import org.joda.beans.Bean; import org.joda.beans.BeanBuilder; import org.joda.beans.JodaBeanUtils; import org.joda.beans.MetaBean; import org.joda.beans.MetaProperty; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; /** * Builder to convert DirectBean to and from Fudge. * * @param <T> the bean type */ public final class NewStyleDirectBeanFudgeBuilder<T extends Bean> implements FudgeBuilder<T> { /** * The meta bean for this instance. */ private final MetaBean _metaBean; /** * Creates a builder from a class, using reflection to find the meta-bean. * @param <R> the bean type * @param cls the class to get the builder for, not null * @return the bean builder, not null */ public static <R extends Bean> NewStyleDirectBeanFudgeBuilder<R> of(final Class<R> cls) { MetaBean meta = JodaBeanUtils.metaBean(cls); return new NewStyleDirectBeanFudgeBuilder<R>(meta); } /** * Constructor. * @param metaBean the meta-bean, not null */ public NewStyleDirectBeanFudgeBuilder(MetaBean metaBean) { _metaBean = metaBean; } //------------------------------------------------------------------------- // TODO: FudgeFieldName and Ordinal annotations @Override public MutableFudgeMsg buildMessage(FudgeSerializer serializer, T bean) { try { MutableFudgeMsg msg = serializer.newMessage(); for (MetaProperty<?> prop : bean.metaBean().metaPropertyIterable()) { if (prop.style().isReadable()) { Object obj = prop.get(bean); serializer.addToMessageWithClassHeaders(msg, prop.name(), null, obj, prop.propertyType()); // ignores null } } addClassHeader(msg, bean.getClass(), Bean.class); return msg; } catch (RuntimeException ex) { throw new FudgeRuntimeException("Unable to serialize: " + _metaBean.beanName(), ex); } } //------------------------------------------------------------------------- @SuppressWarnings("unchecked") @Override public T buildObject(FudgeDeserializer deserializer, FudgeMsg msg) { try { BeanBuilder<T> builder = (BeanBuilder<T>) _metaBean.builder(); for (MetaProperty<?> mp : _metaBean.metaPropertyIterable()) { if (mp.style().isBuildable()) { final FudgeField field = msg.getByName(mp.name()); if (field != null) { Object value; try { //lets try first use type information included in fudge field itself value = deserializer.fieldValueToObject(field); if (!mp.propertyType().isAssignableFrom(value.getClass())) { // the automatically resolved type is not compatible with the bean expected property type. // let's see if we can convert the value to desired type if (mp.propertyType().equals(ImmutableSet.class) && value instanceof Set) { value = ImmutableSet.copyOf((Set<?>) value); } else if (mp.propertyType().equals(ImmutableList.class) && value instanceof List) { value = ImmutableList.copyOf((List<?>) value); } else if (mp.propertyType().equals(ImmutableMap.class) && value instanceof Map) { value = ImmutableMap.copyOf((Map<?, ?>) value); } if (!mp.propertyType().isAssignableFrom(value.getClass())) { // second check of type compatibility // Now we try to deserialise the filed using type hinting. value = deserializer.fieldValueToObject(mp.propertyType(), field); } } } catch (IllegalArgumentException ex) { if (field.getValue() instanceof String == false) { throw ex; } value = JodaBeanUtils.stringConverter().convertFromString(mp.propertyType(), (String) field.getValue()); } if (value != null || mp.propertyType().isPrimitive() == false) { builder.set(mp.name(), value); } } } } return builder.build(); } catch (RuntimeException ex) { throw new FudgeRuntimeException("Unable to deserialize: " + _metaBean.beanName(), ex); } } }