com.sun.webui.jsf.util.ConversionUtilities Maven / Gradle / Ivy
/*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the license at
* https://woodstock.dev.java.net/public/CDDLv1.0.html.
* See the License for the specific language governing
* permissions and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at https://woodstock.dev.java.net/public/CDDLv1.0.html.
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* you own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
*/
/*
* $Id: ConversionUtilities.java,v 1.1.20.1 2009-12-29 04:59:21 jyeary Exp $
*/
/*
* ConversionUtilities.java
*
* Created on December 16, 2004, 8:19 AM
*/
package com.sun.webui.jsf.util;
import java.lang.reflect.Array;
import java.util.HashMap;
import javax.faces.FactoryFinder;
import javax.faces.application.Application;
import javax.faces.application.ApplicationFactory;
import javax.faces.component.UIComponent;
import javax.faces.component.ValueHolder;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.el.ValueExpression;
/**
* The ConversionUtilities class provides utility method for
* converting values to and from Strings. Use this class if
* your component processes input from the user, or displays
* a converted value.
*/
public class ConversionUtilities {
private static final String RENDERED_NULL_VALUE = "_RENDERED_NULL_VALUE_";
private static final boolean DEBUG = false;
/**
* Convert the values of a component with a
* single (non-list, non-array) value. Use this
* method if
*
* - the component always binds the user input to
* a single object (e.g. a textfield component);
* or
* - to handle the single object case when the
* component may bind the user input to a single
* object or to a collection of
* objects (e.g. a list component). Use a
* ValueTypeEvaluator to evaluate the value
* binding type.
*
* @param component The component whose value is getting converted
* @param rawValue The submitted value of the component
* @param context The FacesContext of the request
* @throws ConverterException if the conversion fails
* @return An Object representing the converted value. If rawValue ==
* null
return null.
* @see ValueTypeEvaluator
*/
public static Object convertValueToObject(UIComponent component,
String rawValue,
FacesContext context)
throws ConverterException {
if (DEBUG) {
log("convertValueToObject()");
}
// Optimization based on
// javax.faces.convert.Converter getAsObject.
// It says:
// return null if the value to convert is
// null otherwise the result of the conversion
//
if (rawValue == null || !(component instanceof ValueHolder)) {
return rawValue;
}
ValueHolder valueHolder = ((ValueHolder) component);
Converter converter = valueHolder.getConverter();
if (converter == null) {
Class clazz = null;
// Determine the type of the component's value object
ValueExpression valueBinding =
component.getValueExpression("value"); //NOI18
if (valueBinding == null) {
Object value = valueHolder.getValue();
if (value == null) {
return rawValue;
}
clazz = value.getClass();
} else {
clazz = valueBinding.getType(context.getELContext());
}
// You can't register a default converter for
// String/Object for the whole app (as opposed to for the
// individual component). In this case we just
// return the String.
if (clazz == null || clazz.equals(String.class) || clazz.equals(Object.class)) {
return rawValue;
}
// Try to get a converter
converter = getConverterForClass(clazz);
if (converter == null) {
return rawValue;
}
}
if (DEBUG) {
log("Raw value was: " + rawValue);
log("Converted value is: " + // NOI18N
converter.getAsObject(context, component, rawValue));
}
return converter.getAsObject(context, component, rawValue);
}
/**
* Convert a String array of submitted values to the appropriate
* type of Array for the value Object. This method assumes that
* the value binding for the value of the component has been
* determined to be an array (and as a consequence that the
* component implements ValueHolder).
*
* To evaluate the valueBinding, use the ValueTypeEvaluator
* class.
* @param component The component whose submitted values are to be
* converted
* @param rawValues The submitted value of the component
* @param context The FacesContext of the request
* @see ValueTypeEvaluator
* @throws ConverterException if the conversion fails
* @return An array of converted values
*/
public static Object convertValueToArray(UIComponent component,
String[] rawValues,
FacesContext context)
throws ConverterException {
if (DEBUG) {
log("::convertValueToArray()");
}
// By definition Converter returns null if the value to
// convert is null. Do so here.
//
if (rawValues == null) {
return null;
}
// Get the class of the array members. We expect that the
// component's value binding for its value has been determined
// to be an array, as this is a condition of invoking this
// method.
Class clazz = null;
// Get any converter specified by the page author
Converter converter = ((ValueHolder) component).getConverter();
try {
// Try to obtain the actual value type by obtaining
// the value binding's real value instance and determining its
// type, if the component's defined value type is Object.
//
ValueExpression vb = component.getValueExpression("value"); //NOI18N
Class valueClass = vb.getType(context.getELContext());
if (Object.class.equals(valueClass)) {
Object value = vb.getValue(context.getELContext());
if (value != null) {
valueClass = value.getClass();
}
}
clazz = valueClass.getComponentType();
} catch (Exception ex) {
// This may fail because we don't have a valuebinding (the
// developer may have used the binding attribute)
Object value = ((ValueHolder) component).getValue();
if (value == null) {
// Now we're on thin ice. If there is a converter, we'll
// try to set this as an object array; if not, we'll just
// go for String.
if (converter != null) {
if (DEBUG) {
log("\tNo class info, converter present - using object...");
}
clazz = Object.class;
} else {
if (DEBUG) {
log("\tNo class info, no converter - using String...");
}
clazz = String.class;
}
} else {
clazz = value.getClass().getComponentType();
if (DEBUG) {
log("\tClass is " + clazz.getName());
}
}
}
// If the array members are Strings, no conversion is
// necessary
if (clazz.equals(String.class)) {
if (DEBUG) {
log("\tArray class is String, no conversion necessary");
log("\tValues are ");
for (int counter = 0; counter < rawValues.length; ++counter) {
log("\t" + rawValues[counter]);
}
}
return rawValues;
}
// We know rawValues is not null
//
int arraySize = 0;
arraySize = rawValues.length;
if (DEBUG) {
log("\tNumber of values is " + //NOI18N
String.valueOf(arraySize));
}
Object valueArray = Array.newInstance(clazz, arraySize);
// If there are no new values, return an empty array
if (arraySize == 0) {
if (DEBUG) {
log("\tEmpty value array, return new empty array");
log("\tof type " + valueArray.toString());
}
return valueArray;
}
// Populate the array by converting each of the raw values
// If there is no converter, look for the default converter
if (converter == null) {
if (DEBUG) {
log("\tAttempt to get a default converter");
}
converter = getConverterForClass(clazz);
} else if (DEBUG) {
log("\tRetrieved converter attached to component");
}
int counter;
if (converter == null) {
if (DEBUG) {
log("\tNo converter found");
}
if (clazz.equals(Object.class)) {
if (DEBUG) {
log("\tArray class is object, return the String array");
log("\tValues are\n");
for (counter = 0; counter < rawValues.length; ++counter) {
log("\n" + rawValues[counter]);
}
}
return rawValues;
}
// Failed to deal with submitted data. Throw an
// exception.
String valueString = "";
for (counter = 0; counter < rawValues.length; counter++) {
valueString = valueString + " " + rawValues[counter]; //NOI18N
}
Object[] params = {
valueString,
"null Converter"
};
String message = "Could not find converter for " + valueString;
throw new ConverterException(message);
}
if (clazz.isPrimitive()) {
for (counter = 0; counter < arraySize; ++counter) {
addPrimitiveToArray(component,
context,
converter,
clazz,
valueArray,
counter,
rawValues[counter]);
}
} else {
for (counter = 0; counter < arraySize; ++counter) {
Array.set(valueArray, counter, converter.getAsObject(context, (UIComponent) component, rawValues[counter]));
}
}
return valueArray;
}
private static void addPrimitiveToArray(UIComponent component,
FacesContext context,
Converter converter,
Class clazz,
Object valueArray,
int arrayIndex,
String rawValue) {
Object valueObject =
converter.getAsObject(context, component, rawValue);
if (clazz.equals(Boolean.TYPE)) {
boolean value = ((Boolean) valueObject).booleanValue();
Array.setBoolean(valueArray, arrayIndex, value);
} else if (clazz.equals(Byte.TYPE)) {
byte value = ((Byte) valueObject).byteValue();
Array.setByte(valueArray, arrayIndex, value);
} else if (clazz.equals(Double.TYPE)) {
double value = ((Double) valueObject).doubleValue();
Array.setDouble(valueArray, arrayIndex, value);
} else if (clazz.equals(Float.TYPE)) {
float value = ((Float) valueObject).floatValue();
Array.setFloat(valueArray, arrayIndex, value);
} else if (clazz.equals(Integer.TYPE)) {
int value = ((Integer) valueObject).intValue();
Array.setInt(valueArray, arrayIndex, value);
} else if (clazz.equals(Character.TYPE)) {
char value = ((Character) valueObject).charValue();
Array.setChar(valueArray, arrayIndex, value);
} else if (clazz.equals(Short.TYPE)) {
short value = ((Short) valueObject).shortValue();
Array.setShort(valueArray, arrayIndex, value);
} else if (clazz.equals(Long.TYPE)) {
long value = ((Long) valueObject).longValue();
Array.setLong(valueArray, arrayIndex, value);
}
}
/*
* Convert a String array of submitted values to the appropriate
* type of List for the value Object. This method assumes that
* the value binding for the value of the component has been
* determined to be a subclass of java.util.List, and as a
* consequence, that the component implements ValueHolder.
*
* To evaluate the valueBinding, use the ValueTypeEvaluator
* class.
* @param component The component whose submitted values are to be
* converted
* @param rawValues The submitted value of the component
* @param context The FacesContext of the request
* @see ValueTypeEvaluator
* @throws ConverterException if the conversion fails
*
* @return A List of converted values
public static Object convertValueToList(UIComponent component,
String[] rawValues,
FacesContext context)
throws ConverterException {
if(DEBUG) {
log("::convertValueToList()");
}
// By definition Converter returns null if the value to
// convert is null. Do so here.
//
if (rawValues == null) {
return null;
}
// Get the class of the array members. We expect that the
// component's value binding for its value has been determined
// to be an array, as this is a condition of invoking this
// method.
Class clazz = null;
// Get any converter specified by the page author
Converter converter = ((ValueHolder)component).getConverter();
try {
clazz = component.getValueExpression("value").
getType(context.getELContext()).getComponentType(); //NOI18N
}
catch(Exception ex) {
// This may fail because we don't have a valuebinding (the
// developer may have used the binding attribute)
Object value = ((ValueHolder)component).getValue();
if(value == null) {
// Now we're on thin ice. If there is a converter, we'll
// try to set this as an object array; if not, we'll just
// go for String.
if(converter != null) {
if(DEBUG) log("\tNo class info, converter present - using object...");
clazz = Object.class;
}
else {
if(DEBUG) log("\tNo class info, no converter - using String...");
clazz = String.class;
}
}
else {
clazz = value.getClass().getComponentType();
if(DEBUG) log("\tClass is " + clazz.getName());
}
}
java.util.List list = null;
try {
list = (java.util.List)(clazz.newInstance());
}
catch(Throwable problem) {
// clazz is either abstract or an interface.
// we'll try a couple of reasonable List implementations
if(clazz.isAssignableFrom(ArrayList.class)) {
list = new ArrayList();
}
else if(clazz.isAssignableFrom(LinkedList.class)) {
list = new LinkedList();
}
else if(clazz.isAssignableFrom(Vector.class)) {
list = new Vector();
}
else {
String message =
"Unable to convert the value of component " + //NOI18N
component.toString() + ". The type of the " + //NOI18N
"value object must be a class that can be " + //NOI18N
"instantiated, or it must be assignable " + //NOI18N
"from ArrayList, LinkedList or Vector."; //NOI18N
throw new ConverterException(message, problem);
}
}
// We know rawValues is not null
//
int listSize = 0;
listSize = rawValues.length;
// If there are no new values, return an empty array
if(listSize == 0) {
if(DEBUG) log("\tEmpty value array, return new empty list");
return list;
}
// Populate the list by converting each of the raw values
int arrayIndex;
if(converter == null) {
if(DEBUG) log("No converter, add the values as Strings");
for(arrayIndex = 0; arrayIndex