All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cp.elements.util.convert.provider.DefaultConversionService Maven / Gradle / Ivy

Go to download

Java Simplified. Extensions and Useful Constructs for the Java Platform. Codeprimate Elements (a.k.a. cp-elements) is a Java library and micro-framework used to simplify the development of software applications written in Java. Elements packages several APIs into one library in order to address various application concerns and aspects of software design and development collectively and conveniently. Elements is a highly simple, yet robust and proven library built on solid OO principles, software design patterns and best practices to effectively solve common and reoccurring problems in software development.

There is a newer version: 2.0.0-M1
Show newest version
/*
 * Copyright 2016 Author or Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.cp.elements.util.convert.provider;

import java.io.File;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.cp.elements.io.FileExtensionFilter;
import org.cp.elements.io.FileUtils;
import org.cp.elements.lang.Assert;
import org.cp.elements.lang.ClassUtils;
import org.cp.elements.lang.StringUtils;
import org.cp.elements.util.convert.AbstractConversionService;
import org.cp.elements.util.convert.Converter;
import org.cp.elements.util.convert.support.StringConverter;

/**
 * The DefaultConversionService class is a Service class/component that performs value type conversions.
 *
 * @author John J. Blum
 * @see org.cp.elements.util.convert.AbstractConversionService
 * @see org.cp.elements.util.convert.Converter
 * @see org.cp.elements.util.convert.support.StringConverter
 * @see How can I enumerate all classes in a package and add them to a List?
 * @since 1.0.0
 */
@SuppressWarnings("unused")
public class DefaultConversionService extends AbstractConversionService {

  protected static final Class CONVERTER_CLASS = StringConverter.class;

  protected static final Package CONVERTERS_PACKAGE = CONVERTER_CLASS.getPackage();

  protected static final String CLASS_FILE_EXTENSION = ".class";

  private volatile boolean defaultsEnabled = false;

  private final Map defaultValues = Collections.synchronizedMap(new HashMap<>(13, 0.95f));

  /**
   * Constructs a instance of the DefaultConversionService class to perform type conversions.
   */
  public DefaultConversionService() {
    String converterClassPathname = CONVERTER_CLASS.getName().replace(StringUtils.DOT_SEPARATOR, File.separator)
      .concat(CLASS_FILE_EXTENSION);

    URL converterClassResource = Thread.currentThread().getContextClassLoader().getResource(converterClassPathname);

    Assert.notNull(converterClassResource, "The URL for the Converter class ({0}) pathname ({1}) was null!",
      CONVERTER_CLASS.getName(), converterClassPathname);

    File convertersPackageDirectory;

    try {
      convertersPackageDirectory = new File(converterClassResource.toURI()).getParentFile();
      Assert.isTrue(convertersPackageDirectory.isDirectory(), "The converters package directory ({0}) does not exist!",
        convertersPackageDirectory);
    }
    catch (URISyntaxException e) {
      throw new RuntimeException(String.format("Failed to create a File reference to the converters package directory (%1$s)!",
        converterClassPathname.substring(0, converterClassPathname.lastIndexOf(File.separator) + 1)), e);
    }

    for (File classFile : convertersPackageDirectory.listFiles(new FileExtensionFilter(CLASS_FILE_EXTENSION))) {
      String className = CONVERTERS_PACKAGE.getName().concat(StringUtils.DOT_SEPARATOR).concat(
        FileUtils.getName(classFile));

      Class classType = ClassUtils.loadClass(className);

      if (ClassUtils.assignableTo(classType, Converter.class)) {
        try {
          Converter converter = (Converter) classType.newInstance();
          register(converter);
        }
        catch (Exception ignore) {
          ignore.printStackTrace(System.err);
          // TODO log warning!
        }
      }
    }

    initDefaultValues();
  }

  /**
   * Initializes the default values per Class type to use when the value to convert is null.
   */
  private void initDefaultValues() {
    defaultValues.put(BigDecimal.class, new BigDecimal(0.0d));
    defaultValues.put(BigInteger.class, new BigInteger("0"));
    defaultValues.put(Boolean.class, false);
    defaultValues.put(Byte.class, (byte) 0);
    defaultValues.put(Calendar.class, new CalendarValueGenerator());
    defaultValues.put(Character.class, '\0');
    defaultValues.put(Double.class, 0.0d);
    defaultValues.put(Float.class, 0.0f);
    defaultValues.put(Integer.class, 0);
    defaultValues.put(Long.class, 0l);
    defaultValues.put(Number.class, null);
    defaultValues.put(Short.class, (short) 0);
    defaultValues.put(String.class, null);
  }

  /**
   * Gets the default value for the specified Class type.
   *
   * @param  the classification/type of objects represented by the Class.
   * @param type the Class type to get the default value for.
   * @return the default value for the specified Class type.
   * @see ValueGenerator
   * @see java.lang.Class
   */
  public  T getDefaultValue(final Class type) {
    Object value = defaultValues.get(type);

    if (value instanceof ValueGenerator) {
      value = ((ValueGenerator) value).generateValue();
    }

    return type.cast(value);
  }

  /**
   * Sets the default value for the specified Class type.
   *
   * @param  the classification/type of objects represented by the Class.
   * @param type the Class type to set the default value for.
   * @param defaultValue the default value for the specified Class type.
   * @throws NullPointerException if the Class type is null.
   * @see #setDefaultValue(Class, org.cp.elements.util.convert.provider.DefaultConversionService.ValueGenerator)
   * @see java.lang.Class
   */
  public  void setDefaultValue(final Class type, final T defaultValue) {
    Assert.notNull(type, "The Class type to set the default value for cannot be null!");
    defaultValues.put(type, defaultValue);
  }

  /**
   * Sets the default value for the specified Class type using value generation.
   *
   * @param  the classification/type of objects represented by the Class.
   * @param type the Class type to set the default value for.
   * @param valueGenerator the ValueGenerator used to generate default values for the specified Class type.
   * @throws NullPointerException if the Class type is null.
   * @see #setDefaultValue(Class, Object)
   * @see java.lang.Class
   * @see org.cp.elements.util.convert.provider.DefaultConversionService.ValueGenerator
   */
  public  void setDefaultValue(final Class type, final ValueGenerator valueGenerator) {
    Assert.notNull(type, "The Class type to set the value generator for cannot be null!");
    defaultValues.put(type, valueGenerator);
  }

  /**
   * Unsets the default value for the specified Class type.
   *
   * @param type the Class type to remove the default value for.
   * @see java.lang.Class
   */
  public void unsetDefaultValue(final Class type) {
    defaultValues.remove(type);
  }

  /**
   * Determines whether default values will be used during conversion if the value to convert is null.
   *
   * @return a boolean value indicating whether to use default values during conversion when the value to convert
   * is null.
   */
  public boolean isDefaultValuesEnabled() {
    return defaultsEnabled;
  }

  /**
   * Sets whether default values will be used during conversion if the value to convert is null.
   *
   * @param defaultsEnabled a boolean value to indicate whether to use default values during conversion when
   * the value to convert is null.
   */
  public void setDefaultValuesEnabled(final boolean defaultsEnabled) {
    this.defaultsEnabled = defaultsEnabled;
  }

  /**
   * Determines whether the default value for the specified Class type should be used as the conversion value.
   *
   * @param value the Object value to convert.
   * @param toType the Class type to convert the value to.
   * @return a boolean value indicating whether the default value of the specified Class type should be used.
   */
  protected boolean useDefault(final Object value, final Class toType) {
    return (isDefaultValuesEnabled() && value == null && defaultValues.containsKey(toType));
  }

  /**
   * Converts the Object value into a value of the target Class type.  If the Object value is null and default values
   * are enabled, then the default value based on the Class type to convert to will be returned if the Class type
   * has been set with a default value.
   *
   * @param  the target Class type for the conversion.
   * @param value the Object value to convert.
   * @param toType the Class type to convert the Object value into.
   * @return an instance of the Object value converted into a value of the target Class type, or a default value if
   * the value is null, default values are enabled and the Class type has been set with a default value.
   * @throws org.cp.elements.util.convert.ConversionException if converting the Object value into a value of the target Class type results in error.
   * @see #getDefaultValue(Class)
   * @see java.lang.Class
   * @see org.cp.elements.util.convert.AbstractConversionService#convert(Object, Class)
   * @see org.cp.elements.util.convert.Converter#convert(Object)
   */
  @Override
  public  T convert(final Object value, final Class toType) {
    return (useDefault(value, toType) ? getDefaultValue(toType) : super.convert(value, toType));
  }

  /**
   * The ValueGenerator interface defines contract for implementing objects to generate default values upon request.
   *
   * @param  the type of value to generate.
   */
  public interface ValueGenerator {
    T generateValue();
  }

  /**
   * The CalendarValueGenerator class is a ValueGenerator that creates an instance of Calendar with the
   * current date/time.
   *
   * @see java.util.Calendar
   */
  public static class CalendarValueGenerator implements ValueGenerator {
    @Override
    public Calendar generateValue() {
      return Calendar.getInstance();
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy