Package org.freezedry.persistence.builders

Source Code of org.freezedry.persistence.builders.EnumNodeBuilder

package org.freezedry.persistence.builders;

import org.freezedry.persistence.PersistenceEngine;
import org.freezedry.persistence.annotations.PersistEnum;
import org.freezedry.persistence.tree.InfoNode;
import org.freezedry.persistence.utils.Constants;
import org.freezedry.persistence.utils.ReflectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/**
*
* Created by rob on 3/22/14.
*/
public class EnumNodeBuilder extends AbstractLeafNodeBuilder
{
  private static final Logger LOGGER = LoggerFactory.getLogger( EnumNodeBuilder.class );

  /**
   * Constructs the {@link NodeBuilder} for going between enums and back to {@link Object}s.
   * @param engine The {@link org.freezedry.persistence.PersistenceEngine}
   */
  public EnumNodeBuilder( final PersistenceEngine engine )
  {
    super( engine );
  }

  /**
   * Copy constructor
   * @param builder The {@link org.freezedry.persistence.builders.EnumNodeBuilder} to copy
   */
  public EnumNodeBuilder( final EnumNodeBuilder builder )
  {
    super( builder );
  }

  /**
   * Generates an {@link InfoNode} from the specified {@link Object}. The specified containing {@link Class}
   * is the {@link Class} in which the specified field name lives. And the object is the value of
   * the field name.
   * @param containingClass The {@link Class} that contains the specified field name
   * @param object The value of the field with the specified field name
   * @param fieldName The name of the field for which the object is the value
   * @return The constructed {@link InfoNode} based on the specified information
   */
  @Override
  public InfoNode createInfoNode( final Class<?> containingClass, final Object object, final String fieldName )
  {
    // when the containing class is null, then class is the root node of the semantic model, and therefore
    // there won't be a field name to with a annotation containing the persist name.
    String persistName = null;
    if( containingClass != null )
    {
      // grab the persistence name if the annotation @Persist( persistName = "xxxx" ) is specified,
      // and if the leaf is part of another class (such as a collection) it will return the field name
      persistName = ReflectionUtils.getPersistenceName( containingClass, fieldName );
    }
    if( persistName == null || persistName.isEmpty() )
    {
      persistName = fieldName;
    }

    // grab the value of the enum. in cases where the enum is annotated with "PersistEnum( getValueMethod="...")", we
    // invoke that method.
    final Object value = getEnumValue( containingClass, (Enum)object, fieldName );

    // create a new leaf node with the value of the enum
    return InfoNode.createLeafNode( fieldName, value, persistName, object.getClass() );
  }

  /**
   * Generates an {@link InfoNode} from the specified {@link Object}. This method is used for objects that have
   * an overriding node builder and are not contained within a class. For example, suppose you would like
   * to persist an {@link java.util.ArrayList} for serialization and would like to maintain the type information.
   * @param object The value of the field with the specified field name
   * @return The constructed {@link InfoNode} based on the specified information
   */
  @Override
  public InfoNode createInfoNode( final Object object, final String persistName )
  {
    // create the root node and add the string rep of the date
    final InfoNode node = InfoNode.createRootNode( persistName, object.getClass() );
    node.addChild( InfoNode.createLeafNode( "value", ((Enum)object).name(), "value", String.class ) );

    // return the node
    return node;
  }
  /**
   * Creates an object of the specified {@link Class} based on the information in the {@link InfoNode}. Note that
   * the {@link com.sun.org.apache.xalan.internal.lib.NodeInfo} may also contain type information about the class to generate. The specified {@link Class}
   * overrides that value. This is done to avoid modifying the {@link com.sun.org.apache.xalan.internal.lib.NodeInfo} tree when supplemental information becomes
   * available.
   * @param containingClass The {@link Class} containing the clazz, represented by the {@link InfoNode}
   * @param clazz The {@link Class} of the object to create
   * @param node The information about the object to create
   * @return The object constructed based on the info node.
   */
  @Override
  public Enum createObject( final Class<?> containingClass, final Class<?> clazz, final InfoNode node )
  {
    Enum enumObject = null;
    for( Object constant : clazz.getEnumConstants() )
    {
      if( getEnumValue( containingClass, (Enum)constant, node.getPersistName() ).equals( node.getValue() ) )
      {
        enumObject = (Enum)constant;
        break;
      }
    }
    return enumObject;
  }

  /**
   * Returns the enum value based on the {@link Enum#name()} method, or based on the method specified in the
   * {@link org.freezedry.persistence.annotations.PersistEnum#nameMethod()} ()} annotation
   * @param containingClass The {@link Class} that contains the specified field name
   * @param object The value of the field with the specified field name
   * @param fieldName The name of the field for which the object is the value
   * @return The value of the enum
   */
  private Object getEnumValue( final Class<?> containingClass, final Enum object, final String fieldName )
  {
    Object value = null;
    PersistEnum annotation = null;
    try
    {
      // if the field isn't found or no annotation is present, then we stay
      // with the default date format
      final Field field = ReflectionUtils.getDeclaredField( containingClass, fieldName );
      annotation = field.getAnnotation( PersistEnum.class );
      if( annotation != null )
      {
        value = object.getClass().getMethod( annotation.nameMethod() ).invoke( object );
      }
    }
    catch( NoSuchFieldException e )
    {
      /* empty on purpose, this is ok, just means no annotation */
    }
    catch( NoSuchMethodException e )
    {
      final String error = "The method for getting the enums value specified in the annotation " + PersistEnum.class.getSimpleName() +
          " is not found. Please check the name of the method and compare to the enum you are attempting to persist." +
          "  Containing class: " + containingClass.getSimpleName() + Constants.NEW_LINE +
          "  Field name: " + fieldName + Constants.NEW_LINE +
          "  Annotated method name: " + annotation.nameMethod() + Constants.NEW_LINE;
      LOGGER.error( error, e );
      throw new IllegalStateException( error, e );
    }
    catch( InvocationTargetException | IllegalAccessException e )
    {
      final String error = "The method for getting the enums value specified in the annotation " + PersistEnum.class.getSimpleName() +
          " cannot be invoked." +
          "  Containing class: " + containingClass.getSimpleName() + Constants.NEW_LINE +
          "  Field name: " + fieldName + Constants.NEW_LINE +
          "  Annotated method name: " + annotation.nameMethod() + Constants.NEW_LINE;
      LOGGER.error( error, e );
      throw new IllegalStateException( error, e );
    }

    // grab the enum value using the default enum name
    if( value == null )
    {
      value = object.name();
    }

    return value;
  }

  /**
   * Creates an object of the specified {@link Class} based on the information in the {@link InfoNode}.
   * This method is used for objects that have an overriding node builder and are not contained within a
   * class. For example, suppose you would like to persist an {@link java.util.ArrayList} for serialization and would
   * like to maintain the type information.
   * @param clazz The {@link Class} of the object to create
   * @param node The information about the object to create
   * @return The object constructed based on the info node.
   */
  @Override
  public Enum createObject( final Class< ? > clazz, final InfoNode node )
  {
    return createObject( null, clazz, node.getChild( 0 ) );
  }

  /**
   * Creates and returns a copy of the object <code>x</code> that meets the following criteria
   * <ol>
   *   <li>The expressions <code>x.getCopy() != x</code> evaluates as <code>true</code></li>
   *   <li>The expressions <code>x.getCopy().equals( x )</code> evaluates as <code>true</code></li>
   *   <li>The expressions <code>x.getCopy().getClass() == x.getClass()</code> evaluates as <code>true</code></li>
   * </ol>
   * @return a copy of the object that meets the above criteria
   */
  @Override
  public NodeBuilder getCopy()
  {
    return new EnumNodeBuilder( this );
  }
}
TOP

Related Classes of org.freezedry.persistence.builders.EnumNodeBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.