/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.felix.scr.impl.helper;
import java.lang.reflect.Array;
import java.util.Collection;
import org.osgi.framework.Bundle;
import org.osgi.service.component.ComponentException;
/**
* This implements the coercion table in RFC 190 5.6.3
*
*/
public class Coercions
{
// Numbers are AtomicInteger, AtomicLong, BigDecimal, BigInteger, Byte, Double, Float, Integer, Long, Short
//annotation fields can be primitives, String, Class, enums, annotations, and arrays of the preceding types
// input scalars
// String | Integer | Long | Float
// | Double | Byte | Short
//| Character | Boolean
private static final byte byte0 = 0;
private static final char char0 = 0;
private static final double double0 = 0;
private static final float float0 = 0;
private static final int int0 = 0;
private static final long long0 = 0;
private static final short short0 = 0;
public static Object coerce(Class<?> type, Object raw, Bundle bundle)
{
if ( type == Byte.class || type == byte.class )
{
return coerceToByte( raw );
}
if ( type == Boolean.class || type == boolean.class )
{
return coerceToBoolean( raw );
}
if ( type == Character.class || type == char.class )
{
return coerceToChar( raw );
}
if ( type == Class.class )
{
return coerceToClass( raw, bundle );
}
if ( type == Double.class || type == double.class )
{
return coerceToDouble( raw );
}
if ( type.isEnum() )
{
Class clazz = type; //TODO is there a better way to do ? enum creation?
return coerceToEnum( raw, clazz );
}
if ( type == Float.class || type == float.class )
{
return coerceToFloat( raw );
}
if ( type == Integer.class || type == int.class )
{
return coerceToInteger( raw );
}
if ( type == Long.class || type == long.class )
{
return coerceToLong( raw );
}
if ( type == Short.class || type == short.class )
{
return coerceToShort( raw );
}
if ( type == String.class )
{
return coerceToString( raw );
}
if ( raw != null )
{
raw = multipleToSingle( raw, null );
if ( raw != null )
{
if ( type.isAssignableFrom( raw.getClass() ) )
{
return raw;
}
throw new ComponentException( "unexpected output type " + type );
}
}
return null;
}
public static byte coerceToByte(Object o)
{
o = multipleToSingle( o, byte0 );
if ( o instanceof Byte )
{
return (Byte) o;
}
if ( o instanceof String )
{
try
{
return Byte.parseByte( (String) o );
}
catch ( NumberFormatException e )
{
throw new ComponentException( e );
}
}
if ( o instanceof Boolean )
{
return (Boolean) o? 1: byte0;
}
if ( o instanceof Character )
{
return (byte) ( (Character) o ).charValue();
}
if ( o instanceof Number )
{
return ( (Number) o ).byteValue();
}
if ( o == null )
{
return 0;
}
throw new ComponentException( "Unrecognized input value: " + o + " of type: " + o.getClass() );
}
public static char coerceToChar(Object o)
{
o = multipleToSingle( o, byte0 );
if ( o instanceof Character )
{
return (Character) o;
}
if ( o instanceof String )
{
if ( ( (String) o ).length() > 0 )
{
return ( (String) o ).charAt( 0 );
}
return char0;
}
if ( o instanceof Boolean )
{
return (Boolean) o? 1: char0;
}
if ( o instanceof Number )
{
return (char) ( (Number) o ).intValue();
}
if ( o == null )
{
return char0;
}
throw new ComponentException( "Unrecognized input value: " + o + " of type: " + o.getClass() );
}
public static double coerceToDouble(Object o)
{
o = multipleToSingle( o, double0 );
if ( o instanceof Double )
{
return (Double) o;
}
if ( o instanceof String )
{
try
{
return Double.parseDouble( (String) o );
}
catch ( NumberFormatException e )
{
throw new ComponentException( e );
}
}
if ( o instanceof Boolean )
{
return (Boolean) o? 1: 0;
}
if ( o instanceof Character )
{
return (double) ( (Character) o ).charValue();
}
if ( o instanceof Number )
{
return ( (Number) o ).doubleValue();
}
if ( o == null )
{
return 0;
}
throw new ComponentException( "Unrecognized input value: " + o + " of type: " + o.getClass() );
}
public static float coerceToFloat(Object o)
{
o = multipleToSingle( o, float0 );
if ( o instanceof Float )
{
return (Float) o;
}
if ( o instanceof String )
{
try
{
return Float.parseFloat( (String) o );
}
catch ( NumberFormatException e )
{
throw new ComponentException( e );
}
}
if ( o instanceof Boolean )
{
return (Boolean) o? 1: 0;
}
if ( o instanceof Character )
{
return (float) ( (Character) o ).charValue();
}
if ( o instanceof Number )
{
return ( (Number) o ).floatValue();
}
if ( o == null )
{
return 0;
}
throw new ComponentException( "Unrecognized input value: " + o + " of type: " + o.getClass() );
}
public static int coerceToInteger(Object o)
{
o = multipleToSingle( o, int0 );
if ( o instanceof Integer )
{
return (Integer) o;
}
if ( o instanceof String )
{
try
{
return Integer.parseInt( (String) o );
}
catch ( NumberFormatException e )
{
throw new ComponentException( e );
}
}
if ( o instanceof Boolean )
{
return (Boolean) o? 1: 0;
}
if ( o instanceof Character )
{
return (int) ( (Character) o ).charValue();
}
if ( o instanceof Number )
{
return ( (Number) o ).intValue();
}
if ( o == null )
{
return 0;
}
throw new ComponentException( "Unrecognized input value: " + o + " of type: " + o.getClass() );
}
public static long coerceToLong(Object o)
{
o = multipleToSingle( o, long0 );
if ( o instanceof Long )
{
return (Long) o;
}
if ( o instanceof String )
{
try
{
return Long.parseLong( (String) o );
}
catch ( NumberFormatException e )
{
throw new ComponentException( e );
}
}
if ( o instanceof Boolean )
{
return (Boolean) o? 1: 0;
}
if ( o instanceof Character )
{
return (long) ( (Character) o ).charValue();
}
if ( o instanceof Number )
{
return ( (Number) o ).longValue();
}
if ( o == null )
{
return 0;
}
throw new ComponentException( "Unrecognized input value: " + o + " of type: " + o.getClass() );
}
public static short coerceToShort(Object o)
{
o = multipleToSingle( o, short0 );
if ( o instanceof Short )
{
return (Short) o;
}
if ( o instanceof String )
{
try
{
return Short.parseShort( (String) o );
}
catch ( NumberFormatException e )
{
throw new ComponentException( e );
}
}
if ( o instanceof Boolean )
{
return (Boolean) o? 1: short0;
}
if ( o instanceof Character )
{
return (short) ( (Character) o ).charValue();
}
if ( o instanceof Number )
{
return ( (Number) o ).shortValue();
}
if ( o == null )
{
return 0;
}
throw new ComponentException( "Unrecognized input value: " + o + " of type: " + o.getClass() );
}
public static String coerceToString(Object o)
{
o = multipleToSingle( o, null );
if ( o instanceof String )
{
return (String) o;
}
if ( o == null )
{
return null;
}
return o.toString();
}
public static boolean coerceToBoolean(Object o)
{
o = multipleToSingle( o, false );
if ( o instanceof Boolean )
{
return (Boolean) o;
}
if ( o instanceof String )
{
try
{
return Boolean.parseBoolean( (String) o );
}
catch ( NumberFormatException e )
{
throw new ComponentException( e );
}
}
if ( o instanceof Character )
{
return ( (Character) o ).charValue() != 0;
}
if ( o instanceof Number )
{
return ( (Number) o ).doubleValue() != 0D;
}
if ( o == null )
{
return false;
}
throw new ComponentException( "Unrecognized input value: " + o + " of type: " + o.getClass() );
}
public static Class<?> coerceToClass(Object o, Bundle b)
{
o = multipleToSingle( o, null );
if ( o == null )
{
return null;
}
if ( o instanceof String )
{
try
{
return b.loadClass( (String) o );
}
catch ( ClassNotFoundException e )
{
throw new ComponentException( e );
}
}
throw new ComponentException( "Unrecognized input value: " + o + " of type: " + o.getClass() );
}
public static <T extends Enum<T>> T coerceToEnum(Object o, Class<T> clazz)
{
o = multipleToSingle( o, null );
if ( o instanceof String )
{
try
{
return Enum.valueOf( clazz, (String) o );
}
catch ( IllegalArgumentException e )
{
throw new ComponentException( e );
}
}
if ( o == null )
{
return null;
}
throw new ComponentException( "Unrecognized input value: " + o + " of type: " + o.getClass() );
}
private static Object multipleToSingle(Object o, Object defaultValue)
{
if ( o instanceof Collection )
{
return firstCollectionElement( o, defaultValue );
}
if ( o != null && o.getClass().isArray() )
{
return firstArrayElement( o, defaultValue );
}
return o;
}
private static Object firstCollectionElement(Object raw, Object defaultValue)
{
if ( !( raw instanceof Collection ) )
{
throw new ComponentException( "Not a collection: " + raw );
}
Collection<?> c = (Collection<?>) raw;
if ( c.isEmpty() )
{
return defaultValue;
}
return c.iterator().next();
}
private static Object firstArrayElement(Object o, Object defaultValue)
{
if ( o == null || !o.getClass().isArray() )
{
throw new ComponentException( "Not an array: " + o );
}
if ( Array.getLength( o ) == 0 )
{
return defaultValue;
}
return Array.get( o, 0 );
}
}