
org.nerd4j.csv.registry.CSVFieldConverterRegistry Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nerd4j-csv Show documentation
Show all versions of nerd4j-csv Show documentation
CSV manipulation library.
The newest version!
/*
* #%L
* Nerd4j CSV
* %%
* Copyright (C) 2013 Nerd4j
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
package org.nerd4j.csv.registry;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.nerd4j.csv.exception.CSVConfigurationException;
import org.nerd4j.csv.field.CSVFieldConverter;
import org.nerd4j.csv.field.converter.BooleanToString;
import org.nerd4j.csv.field.converter.DateToString;
import org.nerd4j.csv.field.converter.EmptyCSVFieldConverter;
import org.nerd4j.csv.field.converter.EnumToString;
import org.nerd4j.csv.field.converter.NumberToString;
import org.nerd4j.csv.field.converter.StringToBoolean;
import org.nerd4j.csv.field.converter.StringToDate;
import org.nerd4j.csv.field.converter.StringToEnum;
import org.nerd4j.csv.field.converter.StringToNumber;
import org.nerd4j.i18n.LocaleUtil;
/**
* Represents a registry of {@link CSVFieldConverter}s.
*
*
* This registry is internally used to refer {@link CSVFieldConverter}s by name.
* It is possible to register custom providers able to provide custom converters.
*
*
* The following converters are registered by default:
*
* - parseByte : pattern = the number parse pattern (optional)
* locale = the pattern locale for symbols (optional)
* - parseShort : pattern = the number parse pattern (optional)
* locale = the pattern locale for symbols (optional)
* - parseInteger : pattern = the number parse pattern (optional)
* locale = the pattern locale for symbols (optional)
* - parseLong : pattern = the number parse pattern (optional)
* locale = the pattern locale for symbols (optional)
* - parseFloat : pattern = the number parse pattern (optional)
* locale = the pattern locale for symbols (optional)
* - parseDouble : pattern = the number parse pattern (optional)
* locale = the pattern locale for symbols (optional)
* - parseBigInteger : pattern = the number parse pattern (optional)
* locale = the pattern locale for symbols (optional)
* - parseBigDecimal : pattern = the number parse pattern (optional)
* locale = the pattern locale for symbols (optional)
* - parseAtomicInteger : pattern = the number parse pattern (optional)
* locale = the pattern locale for symbols (optional)
* - parseAtomicLong : pattern = the number parse pattern (optional)
* locale = the pattern locale for symbols (optional)
*
* - formatByte : pattern = the number format pattern (optional)
* locale = the pattern locale for symbols (optional)
* - formatShort : pattern = the number format pattern (optional)
* locale = the pattern locale for symbols (optional)
* - formatInteger : pattern = the number format pattern (optional)
* locale = the pattern locale for symbols (optional)
* - formatLong : pattern = the number format pattern (optional)
* locale = the pattern locale for symbols (optional)
* - formatFloat : pattern = the number format pattern (optional)
* locale = the pattern locale for symbols (optional)
* - formatDouble : pattern = the number format pattern (optional)
* locale = the pattern locale for symbols (optional)
* - formatBigInteger : pattern = the number format pattern (optional)
* locale = the pattern locale for symbols (optional)
* - formatBigDecimal : pattern = the number format pattern (optional)
* locale = the pattern locale for symbols (optional)
* - formatAtomicInteger: pattern = the number format pattern (optional)
* locale = the pattern locale for symbols (optional)
* - formatAtomicLong : pattern = the number format pattern (optional)
* locale = the pattern locale for symbols (optional)
*
* - parseBoolean : no parameters
* - formatBoolean : no parameters
*
* - parseDate : pattern = the date format pattern (mandatory)
* time-zone = input date timezone (optional)
* locale = the pattern locale for symbols (optional)
* - formatDate : pattern = the date format pattern (mandatory)
* time-zone = output date timezone (optional)
* locale = the pattern locale for symbols (optional)
*
* - parseEnum : enum-type = the fully qualified enum class name (mandatory)
* - formatEnum : enum-type = the fully qualified enum class name (mandatory)
*
*
* @author Nerd4j Team
*/
final class CSVFieldConverterRegistry extends CSVAbstractRegistry>
{
/**
* Default constructor.
*
*/
public CSVFieldConverterRegistry()
{
super();
this.registerDefaults();
}
/* *************** */
/* INNER CLASSES */
/* *************** */
/**
* Represents a provider able to create {@link String} to {@link Number} converters.
*
* @param type of the {@link Number} to be returned.
*
* @author Nerd4j Team
*/
private static final class StringToNumberProvider implements CSVRegistryEntryProvider>
{
/** The type of the {@link Number} to be returned. */
private final Class numberType;
/**
* Constructor with parameters.
*
* @param numberType one of the accepted implementations of the {@link Number}.
*/
public StringToNumberProvider( final Class numberType )
{
super();
this.numberType = numberType;
}
/**
* {@inheritDoc}
*/
@Override
public CSVFieldConverter get( Map params )
{
final String pattern = params.get("pattern");
final String nlocale = params.get("locale");
final Locale locale = nlocale == null ? null : LocaleUtil.getLocale(nlocale);
return new StringToNumber( numberType, pattern, locale );
}
/**
* {@inheritDoc}
*/
@Override
public void validate( Map params )
{
if( params == null || params.isEmpty() ) return;
try{
final String pattern = params.get( "pattern" );
if( pattern != null && ! pattern.isEmpty() )
new DecimalFormat( pattern );
final String locale = params.get( "locale" );
if( locale != null && ! locale.isEmpty() )
LocaleUtil.getLocale( locale );
}catch( Exception ex )
{
throw new CSVConfigurationException( ex );
}
}
}
/**
* Represents a provider able to create {@link Number} to {@link String} converters.
*
* @param type of the {@link Number} to be returned.
*
* @author Nerd4j Team
*/
private static final class NumberToStringProvider implements CSVRegistryEntryProvider>
{
/** The type of the {@link Number} to be provided. */
private final Class numberType;
/**
* Constructor with parameters.
*
* @param numberType one of the accepted implementations of the {@link Number}.
*/
public NumberToStringProvider( final Class numberType )
{
super();
this.numberType = numberType;
}
/**
* {@inheritDoc}
*/
@Override
public CSVFieldConverter get( Map params )
{
final String pattern = params.get("pattern");
final String nlocale = params.get("locale");
final Locale locale = nlocale == null ? null : LocaleUtil.getLocale(nlocale);
return new NumberToString( numberType, pattern, locale );
}
/**
* {@inheritDoc}
*/
@Override
public void validate( Map params )
{
if( params == null || params.isEmpty() ) return;
try{
final String pattern = params.get( "pattern" );
if( pattern != null && ! pattern.isEmpty() )
new DecimalFormat( pattern );
final String locale = params.get( "locale" );
if( locale != null && ! locale.isEmpty() )
LocaleUtil.getLocale( locale );
}catch( Exception ex )
{
throw new CSVConfigurationException( ex );
}
}
}
/* ***************** */
/* PRIVATE METHODS */
/* ***************** */
/**
* Creates and registers the default entries and providers.
*
*/
@SuppressWarnings("rawtypes")
private void registerDefaults()
{
/* The empty converter to use in case of missing configuration. */
setFactory( "default", new CSVRegistryEntryFactory>()
{
/** Singleton instance of the empty converter. */
private final CSVFieldConverter,?> emptyConverter = new EmptyCSVFieldConverter( String.class );
/**
* {@inheritDoc}
*/
@Override
public CSVFieldConverter,?> create()
{
return emptyConverter;
}
});
/* String to Number Providers. */
setProvider( "parseByte", new StringToNumberProvider(Byte.class) );
setProvider( "parseShort", new StringToNumberProvider(Short.class) );
setProvider( "parseInteger", new StringToNumberProvider(Integer.class) );
setProvider( "parseLong", new StringToNumberProvider(Long.class) );
setProvider( "parseFloat", new StringToNumberProvider(Float.class) );
setProvider( "parseDouble", new StringToNumberProvider(Double.class) );
setProvider( "parseBigInteger", new StringToNumberProvider(BigInteger.class) );
setProvider( "parseBigDecimal", new StringToNumberProvider(BigDecimal.class) );
setProvider( "parseAtomicInteger", new StringToNumberProvider(AtomicInteger.class) );
setProvider( "parseAtomicLong", new StringToNumberProvider(AtomicLong.class) );
/* Number to String Providers. */
setProvider( "formatByte", new NumberToStringProvider(Byte.class) );
setProvider( "formatShort", new NumberToStringProvider(Short.class) );
setProvider( "formatInteger", new NumberToStringProvider(Integer.class) );
setProvider( "formatLong", new NumberToStringProvider(Long.class) );
setProvider( "formatFloat", new NumberToStringProvider(Float.class) );
setProvider( "formatDouble", new NumberToStringProvider(Double.class) );
setProvider( "formatBigInteger", new NumberToStringProvider(BigInteger.class) );
setProvider( "formatBigDecimal", new NumberToStringProvider(BigDecimal.class) );
setProvider( "formatAtomicInteger", new NumberToStringProvider(AtomicInteger.class) );
setProvider( "formatAtomicLong", new NumberToStringProvider(AtomicLong.class) );
/* String to Boolean Provider. */
setProvider( "parseBoolean", new CSVRegistryEntryProvider>()
{
/**
* {@inheritDoc}
*/
@Override
public CSVFieldConverter get( Map params )
{
return new StringToBoolean();
}
/**
* {@inheritDoc}
*/
@Override
public void validate( Map params ) {}
});
/* Boolean to String Provider. */
setProvider( "formatBoolean", new CSVRegistryEntryProvider>()
{
/**
* {@inheritDoc}
*/
@Override
public CSVFieldConverter get( Map params )
{
return new BooleanToString();
}
/**
* {@inheritDoc}
*/
@Override
public void validate( Map params ) {}
});
/* String to Date Provider. */
setProvider( "parseDate", new CSVRegistryEntryProvider>()
{
/**
* {@inheritDoc}
*/
@Override
public CSVFieldConverter get( Map params )
{
final String pattern = params.get( "pattern" );
final String timeZoneID = params.get( "time-zone" );
final String dlocale = params.get( "locale" );
final TimeZone timeZone;
if( timeZoneID == null )
{
timeZone = TimeZone.getDefault();
}
else
{
/*
* A nasty trick to walk around implicit GMT timezone got
* from TimeZone.getTimeZone(timeZoneID ) if timeZoneId
* cannot be converted to any useful value.
*/
timeZone = TimeZone.getTimeZone( timeZoneID );
/* Not nullable, is at least GMT */
final String tzID = timeZone.getID();
/*
* Check if got timezone is a GMT default o real value.
* If is a default throw exception.
*/
if ( tzID.equals( "GMT" ) && !tzID.equals( timeZoneID ) )
throw new CSVConfigurationException( "The value time-zone (" +
timeZoneID + ") do not represent a TimeZone identifier" );
}
final Locale locale = dlocale == null ? null : LocaleUtil.getLocale(dlocale);
return new StringToDate( pattern, timeZone, locale );
}
/**
* {@inheritDoc}
*/
@Override
public void validate( Map params )
{
if( params == null || params.isEmpty() ) return;
try{
final String pattern = params.get( "pattern" );
if( pattern != null && ! pattern.isEmpty() )
new SimpleDateFormat( pattern );
final String locale = params.get( "locale" );
if( locale != null && ! locale.isEmpty() )
LocaleUtil.getLocale( locale );
final String timezone = params.get( "time-zone" );
if( timezone != null && ! timezone.isEmpty() )
TimeZone.getTimeZone( timezone );
}catch( Exception ex )
{
throw new CSVConfigurationException( ex );
}
}
});
/* Date to String Provider. */
setProvider( "formatDate", new CSVRegistryEntryProvider>()
{
/**
* {@inheritDoc}
*/
@Override
public CSVFieldConverter get( Map params )
{
final String pattern = params.get( "pattern" );
final String timeZoneID = params.get( "time-zone" );
final String dlocale = params.get( "locale" );
final TimeZone timeZone;
if( timeZoneID == null )
{
timeZone = TimeZone.getDefault();
}
else
{
/*
* A nasty trick to walk around implicit GMT timezone got
* from TimeZone.getTimeZone(timeZoneID ) if timeZoneId
* cannot be converted to any useful value.
*/
timeZone = TimeZone.getTimeZone( timeZoneID );
/* Not nullable, is at least GMT */
final String tzID = timeZone.getID();
/*
* Check if got timezone is a GMT default o real value.
* If is a default throw exception.
*/
if ( tzID.equals( "GMT" ) && !tzID.equals( timeZoneID ) )
throw new CSVConfigurationException( "The value time-zone (" +
timeZoneID + ") do not represent a TimeZone identifier" );
}
final Locale locale = dlocale == null ? null : LocaleUtil.getLocale(dlocale);
return new DateToString( pattern, timeZone, locale );
}
/**
* {@inheritDoc}
*/
@Override
public void validate( Map params )
{
if( params == null || params.isEmpty() ) return;
try{
final String pattern = params.get( "pattern" );
if( pattern != null && ! pattern.isEmpty() )
new SimpleDateFormat( pattern );
final String locale = params.get( "locale" );
if( locale != null && ! locale.isEmpty() )
LocaleUtil.getLocale( locale );
final String timezone = params.get( "time-zone" );
if( timezone != null && ! timezone.isEmpty() )
TimeZone.getTimeZone( timezone );
}catch( Exception ex )
{
throw new CSVConfigurationException( ex );
}
}
});
/* String to Enum Provider. */
setProvider( "parseEnum", new CSVRegistryEntryProvider>()
{
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings({ "unchecked" })
public CSVFieldConverter> get( Map params )
{
final String enumType = params.get( "enum-type" );
if( enumType == null )
throw new CSVConfigurationException( "The enum-type is mandatory to build parseEnum" );
try{
final Class> enumClass = Class.forName( enumType );
if( ! enumClass.isEnum() )
throw new CSVConfigurationException( "The value enum-type to not represent an enum" );
return new StringToEnum( enumClass );
}catch( ClassNotFoundException ex )
{
throw new CSVConfigurationException( "The value enum-type do not represent a canonical class name", ex );
}
}
/**
* {@inheritDoc}
*/
@Override
public void validate( Map params )
{
if( params == null || params.isEmpty() )
throw new CSVConfigurationException( "The parameter enum-type is mandatory" );
final String enumType = params.get( "enum-type" );
if( enumType == null )
throw new CSVConfigurationException( "The parameter enum-type is mandatory." );
try{
final Class> enumClass = Class.forName( enumType );
if( ! enumClass.isEnum() )
throw new CSVConfigurationException( "The value enum-type to not represent an enum" );
}catch( ClassNotFoundException ex )
{
throw new CSVConfigurationException( "The value enum-type do not represent a canonical class name", ex );
}
}
});
/* Enum to String Provider. */
setProvider( "formatEnum", new CSVRegistryEntryProvider>()
{
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings({ "unchecked" })
public CSVFieldConverter,String> get( Map params )
{
final String enumType = params.get( "enum-type" );
if( enumType == null )
throw new CSVConfigurationException( "The enum-type is mandatory to build formatEnum" );
try{
final Class> enumClass = Class.forName( enumType );
if( ! enumClass.isEnum() )
throw new CSVConfigurationException( "The value enum-type do not represent an enum" );
return new EnumToString( enumClass );
}catch( ClassNotFoundException ex )
{
throw new CSVConfigurationException( "The value enum-type do not represent a canonical class name", ex );
}
}
/**
* {@inheritDoc}
*/
@Override
public void validate( Map params )
{
if( params == null || params.isEmpty() )
throw new CSVConfigurationException( "The parameter enum-type is mandatory" );
final String enumType = params.get( "enum-type" );
if( enumType == null )
throw new CSVConfigurationException( "The parameter enum-type is mandatory." );
try{
final Class> enumClass = Class.forName( enumType );
if( ! enumClass.isEnum() )
throw new CSVConfigurationException( "The value enum-type to not represent an enum" );
}catch( ClassNotFoundException ex )
{
throw new CSVConfigurationException( "The value enum-type do not represent a canonical class name", ex );
}
}
});
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy