alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Struts example source code file (XWorkBasicConverter.java)

This example Struts source code file (XWorkBasicConverter.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Struts tags/keywords

biginteger, class, class, collection, date, dateformat, dateformat, math, number, object, object, reflection, simpledateformat, string, string, text, util, xworkexception

The Struts XWorkBasicConverter.java source code

/*
 * Copyright 2002-2007,2009 The Apache Software Foundation.
 * 
 * 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 com.opensymphony.xwork2.conversion.impl;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ObjectFactory;
import com.opensymphony.xwork2.XWorkException;
import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer;
import com.opensymphony.xwork2.conversion.TypeConverter;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.XWorkList;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Member;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.*;
import java.util.*;

import org.apache.commons.lang.StringUtils;


/**
 * <!-- START SNIPPET: javadoc -->
 * <p/>
 * XWork will automatically handle the most common type conversion for you. This includes support for converting to
 * and from Strings for each of the following:
 * <p/>
 * <ul>
 * <li>String
 * <li>boolean / Boolean
 * <li>char / Character
 * <li>int / Integer, float / Float, long / Long, double / Double
 * <li>dates - uses the SHORT format for the Locale associated with the current request
 * <li>arrays - assuming the individual strings can be coverted to the individual items
 * <li>collections - if not object type can be determined, it is assumed to be a String and a new ArrayList is
 * created</li>
 * </ul>
 * <p/> Note that with arrays the type conversion will defer to the type of the array elements and try to convert each
 * item individually. As with any other type conversion, if the conversion can't be performed the standard type
 * conversion error reporting is used to indicate a problem occured while processing the type conversion.
 * <p/>
 * <!-- END SNIPPET: javadoc -->
 *
 * @author <a href="mailto:plightbo@gmail.com">Pat Lightbody
 * @author Mike Mosiewicz
 * @author Rainer Hermanns
 * @author <a href='mailto:the_mindstorm[at]evolva[dot]ro'>Alexandru Popescu
 */
public class XWorkBasicConverter extends DefaultTypeConverter {

    private static String MILLISECOND_FORMAT = ".SSS";
    
    private ObjectTypeDeterminer objectTypeDeterminer;
    private XWorkConverter xworkConverter;
    private ObjectFactory objectFactory;

    @Inject
    public void setObjectTypeDeterminer(ObjectTypeDeterminer det) {
        this.objectTypeDeterminer = det;
    }
    
    @Inject
    public void setXWorkConverter(XWorkConverter conv) {
        this.xworkConverter = conv;
    }
    
    @Inject
    public void setObjectFactory(ObjectFactory fac) {
        this.objectFactory = fac;
    }

    @Override
    public Object convertValue(Map<String, Object> context, Object o, Member member, String s, Object value, Class toType) {
        Object result = null;

        if (value == null || toType.isAssignableFrom(value.getClass())) {
            // no need to convert at all, right?
            return value;
        }

        if (toType == String.class) {
            /* the code below has been disabled as it causes sideffects in Struts2 (XW-512)
            // if input (value) is a number then use special conversion method (XW-490)
            Class inputType = value.getClass();
            if (Number.class.isAssignableFrom(inputType)) {
                result = doConvertFromNumberToString(context, value, inputType);
                if (result != null) {
                    return result;
                }
            }*/
            // okay use default string conversion
            result = doConvertToString(context, value);
        } else if (toType == boolean.class) {
            result = doConvertToBoolean(value);
        } else if (toType == Boolean.class) {
            result = doConvertToBoolean(value);
        } else if (toType.isArray()) {
            result = doConvertToArray(context, o, member, s, value, toType);
        } else if (Date.class.isAssignableFrom(toType)) {
            result = doConvertToDate(context, value, toType);
        } else if (Calendar.class.isAssignableFrom(toType)) {
            Date dateResult = (Date) doConvertToDate(context, value, Date.class);
            if (dateResult != null) {
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(dateResult);
                result = calendar;
            } 
        } else if (Collection.class.isAssignableFrom(toType)) {
            result = doConvertToCollection(context, o, member, s, value, toType);
        } else if (toType == Character.class) {
            result = doConvertToCharacter(value);
        } else if (toType == char.class) {
            result = doConvertToCharacter(value);
        } else if (Number.class.isAssignableFrom(toType) || toType.isPrimitive()) {
            result = doConvertToNumber(context, value, toType);
        } else if (toType == Class.class) {
            result = doConvertToClass(value);
        }

        if (result == null) {
            if (value instanceof Object[]) {
                Object[] array = (Object[]) value;

                if (array.length >= 1) {
                    value = array[0];
                } else {
                    value = null;
                }

                // let's try to convert the first element only
                result = convertValue(context, o, member, s, value, toType);
            } else if (!"".equals(value)) { // we've already tried the types we know
                result = super.convertValue(context, value, toType);
            }

            if (result == null && value != null && !"".equals(value)) {
                throw new XWorkException("Cannot create type " + toType + " from value " + value);
            }
        }

        return result;
    }

    private Locale getLocale(Map<String, Object> context) {
        if (context == null) {
            return Locale.getDefault();
        }

        Locale locale = (Locale) context.get(ActionContext.LOCALE);

        if (locale == null) {
            locale = Locale.getDefault();
        }

        return locale;
    }

    /**
     * Creates a Collection of the specified type.
     *
     * @param fromObject
     * @param propertyName
     * @param toType       the type of Collection to create
     * @param memberType   the type of object elements in this collection must be
     * @param size         the initial size of the collection (ignored if 0 or less)
     * @return a Collection of the specified type
     */
    private Collection createCollection(Object fromObject, String propertyName, Class toType, Class memberType, int size) {
//        try {
//            Object original = Ognl.getValue(OgnlUtil.compile(propertyName),fromObject);
//            if (original instanceof Collection) {
//                Collection coll = (Collection) original;
//                coll.clear();
//                return coll;
//            }
//        } catch (Exception e) {
//            // fail back to creating a new one
//        }

        Collection result;

        if (toType == Set.class) {
            if (size > 0) {
                result = new HashSet(size);
            } else {
                result = new HashSet();
            }
        } else if (toType == SortedSet.class) {
            result = new TreeSet();
        } else {
            if (size > 0) {
                result = new XWorkList(objectFactory, xworkConverter, memberType, size);
            } else {
                result = new XWorkList(objectFactory, xworkConverter, memberType);
            }
        }

        return result;
    }

    private Object doConvertToArray(Map<String, Object> context, Object o, Member member, String s, Object value, Class toType) {
        Object result = null;
        Class componentType = toType.getComponentType();

        if (componentType != null) {
            TypeConverter converter = getTypeConverter(context);

            if (value.getClass().isArray()) {
                int length = Array.getLength(value);
                result = Array.newInstance(componentType, length);

                for (int i = 0; i < length; i++) {
                    Object valueItem = Array.get(value, i);
                    Array.set(result, i, converter.convertValue(context, o, member, s, valueItem, componentType));
                }
            } else {
                result = Array.newInstance(componentType, 1);
                Array.set(result, 0, converter.convertValue(context, o, member, s, value, componentType));
            }
        }

        return result;
    }

    private Object doConvertToCharacter(Object value) {
        if (value instanceof String) {
            String cStr = (String) value;

            return (cStr.length() > 0) ? new Character(cStr.charAt(0)) : null;
        }

        return null;
    }

    private Object doConvertToBoolean(Object value) {
        if (value instanceof String) {
            String bStr = (String) value;

            return Boolean.valueOf(bStr);
        }

        return null;
    }

    private Class doConvertToClass(Object value) {
        Class clazz = null;

        if (value instanceof String && value != null && ((String) value).length() > 0) {
            try {
                clazz = Class.forName((String) value);
            } catch (ClassNotFoundException e) {
                throw new XWorkException(e.getLocalizedMessage(), e);
            }
        }

        return clazz;
    }

    private Collection doConvertToCollection(Map<String, Object> context, Object o, Member member, String prop, Object value, Class toType) {
        Collection result;
        Class memberType = String.class;

        if (o != null) {
            //memberType = (Class) XWorkConverter.getInstance().getConverter(o.getClass(), XWorkConverter.CONVERSION_COLLECTION_PREFIX + prop);
            memberType = objectTypeDeterminer.getElementClass(o.getClass(), prop, null);

            if (memberType == null) {
                memberType = String.class;
            }
        }

        if (toType.isAssignableFrom(value.getClass())) {
            // no need to do anything
            result = (Collection) value;
        } else if (value.getClass().isArray()) {
            Object[] objArray = (Object[]) value;
            TypeConverter converter = getTypeConverter(context);
            result = createCollection(o, prop, toType, memberType, objArray.length);

            for (Object anObjArray : objArray) {
                result.add(converter.convertValue(context, o, member, prop, anObjArray, memberType));
            }
        } else if (Collection.class.isAssignableFrom(value.getClass())) {
            Collection col = (Collection) value;
            TypeConverter converter = getTypeConverter(context);
            result = createCollection(o, prop, toType, memberType, col.size());

            for (Object aCol : col) {
                result.add(converter.convertValue(context, o, member, prop, aCol, memberType));
            }
        } else {
            result = createCollection(o, prop, toType, memberType, -1);
            result.add(value);
        }

        return result;
    }

    private Object doConvertToDate(Map<String, Object> context, Object value, Class toType) {
        Date result = null;

        if (value instanceof String && value != null && ((String) value).length() > 0) {
            String sa = (String) value;
            Locale locale = getLocale(context);

            DateFormat df = null;
            if (java.sql.Time.class == toType) {
                df = DateFormat.getTimeInstance(DateFormat.MEDIUM, locale);
            } else if (java.sql.Timestamp.class == toType) {
                Date check = null;
                SimpleDateFormat dtfmt = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT,
                        DateFormat.MEDIUM,
                        locale);
                SimpleDateFormat fullfmt = new SimpleDateFormat(dtfmt.toPattern() + MILLISECOND_FORMAT,
                        locale);

                SimpleDateFormat dfmt = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT,
                        locale);

                SimpleDateFormat[] fmts = {fullfmt, dtfmt, dfmt};
                for (SimpleDateFormat fmt : fmts) {
                    try {
                        check = fmt.parse(sa);
                        df = fmt;
                        if (check != null) {
                            break;
                        }
                    } catch (ParseException ignore) {
                    }
                }
            } else if (java.util.Date.class == toType) {
                Date check = null;
                DateFormat[] dfs = getDateFormats(locale);
                for (DateFormat df1 : dfs) {
                    try {
                        check = df1.parse(sa);
                        df = df1;
                        if (check != null) {
                            break;
                        }
                    }
                    catch (ParseException ignore) {
                    }
                }
            }
            //final fallback for dates without time
            if (df == null) {
                df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
            }
            try {
                df.setLenient(false); // let's use strict parsing (XW-341)
                result = df.parse(sa);
                if (!(Date.class == toType)) {
                    try {
                        Constructor constructor = toType.getConstructor(new Class[]{long.class});
                        return constructor.newInstance(new Object[]{Long.valueOf(result.getTime())});
                    } catch (Exception e) {
                        throw new XWorkException("Couldn't create class " + toType + " using default (long) constructor", e);
                    }
                }
            } catch (ParseException e) {
                throw new XWorkException("Could not parse date", e);
            }
        } else if (Date.class.isAssignableFrom(value.getClass())) {
            result = (Date) value;
        }
        return result;
    }

    private DateFormat[] getDateFormats(Locale locale) {
        DateFormat dt1 = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG, locale);
        DateFormat dt2 = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, locale);
        DateFormat dt3 = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, locale);

        DateFormat d1 = DateFormat.getDateInstance(DateFormat.SHORT, locale);
        DateFormat d2 = DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
        DateFormat d3 = DateFormat.getDateInstance(DateFormat.LONG, locale);

        DateFormat rfc3399 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");

        DateFormat[] dfs = {dt1, dt2, dt3, rfc3399, d1, d2, d3}; //added RFC 3339 date format (XW-473)
        return dfs;
    }

    private Object doConvertToNumber(Map<String, Object> context, Object value, Class toType) {
        if (value instanceof String) {
            if (toType == BigDecimal.class) {
                return new BigDecimal((String) value);
            } else if (toType == BigInteger.class) {
                return new BigInteger((String) value);
            } else if (toType.isPrimitive()) {
                Object convertedValue = super.convertValue(context, value, toType);
                String stringValue = (String) value;
                if (!isInRange((Number)convertedValue, stringValue,  toType))
                        throw new XWorkException("Overflow or underflow casting: \"" + stringValue + "\" into class " + convertedValue.getClass().getName());

                return convertedValue;
            } else {
                String stringValue = (String) value;
                if (!toType.isPrimitive() && (stringValue == null || stringValue.length() == 0)) {
                    return null;
                }
                NumberFormat numFormat = NumberFormat.getInstance(getLocale(context));
                ParsePosition parsePos = new ParsePosition(0);
                if (isIntegerType(toType)) {
                    numFormat.setParseIntegerOnly(true);
                }
                numFormat.setGroupingUsed(true);
                Number number = numFormat.parse(stringValue, parsePos);

                if (parsePos.getIndex() != stringValue.length()) {
                    throw new XWorkException("Unparseable number: \"" + stringValue + "\" at position "
                            + parsePos.getIndex());
                } else {
                    if (!isInRange(number, stringValue,  toType))
                        throw new XWorkException("Overflow or underflow casting: \"" + stringValue + "\" into class " + number.getClass().getName());
                    
                    value = super.convertValue(context, number, toType);
                }
            }
        } else if (value instanceof Object[]) {
            Object[] objArray = (Object[]) value;

            if (objArray.length == 1) {
                return doConvertToNumber(context, objArray[0], toType);
            }
        }

        // pass it through DefaultTypeConverter
        return super.convertValue(context, value, toType);
    }

    protected boolean isInRange(Number value, String stringValue, Class toType) {
        Number bigValue = null;
        Number lowerBound = null;
        Number upperBound = null;

        try {
            if (double.class == toType || Double.class == toType) {
                bigValue = new BigDecimal(stringValue);
                // Double.MIN_VALUE is the smallest positive non-zero number
                lowerBound = BigDecimal.valueOf(Double.MAX_VALUE).negate();
                upperBound = BigDecimal.valueOf(Double.MAX_VALUE);
            } else if (float.class == toType || Float.class == toType) {
                bigValue = new BigDecimal(stringValue);
                // Float.MIN_VALUE is the smallest positive non-zero number
                lowerBound = BigDecimal.valueOf(Float.MAX_VALUE).negate();
                upperBound = BigDecimal.valueOf(Float.MAX_VALUE);
            } else if (byte.class == toType || Byte.class == toType) {
                bigValue = new BigInteger(stringValue);
                lowerBound = BigInteger.valueOf(Byte.MIN_VALUE);
                upperBound = BigInteger.valueOf(Byte.MAX_VALUE);
            } else if (char.class == toType || Character.class == toType) {
                bigValue = new BigInteger(stringValue);
                lowerBound = BigInteger.valueOf(Character.MIN_VALUE);
                upperBound = BigInteger.valueOf(Character.MAX_VALUE);
            } else if (short.class == toType || Short.class == toType) {
                bigValue = new BigInteger(stringValue);
                lowerBound = BigInteger.valueOf(Short.MIN_VALUE);
                upperBound = BigInteger.valueOf(Short.MAX_VALUE);
            } else if (int.class == toType || Integer.class == toType) {
                bigValue = new BigInteger(stringValue);
                lowerBound = BigInteger.valueOf(Integer.MIN_VALUE);
                upperBound = BigInteger.valueOf(Integer.MAX_VALUE);
            } else if (long.class == toType || Long.class == toType) {
                bigValue = new BigInteger(stringValue);
                lowerBound = BigInteger.valueOf(Long.MIN_VALUE);
                upperBound = BigInteger.valueOf(Long.MAX_VALUE);
            }
        } catch (NumberFormatException e) {
            //shoult it fail here? BigInteger doesnt seem to be so nice parsing numbers as NumberFormat
            return true;
        }

        return ((Comparable)bigValue).compareTo(lowerBound) >= 0 && ((Comparable)bigValue).compareTo(upperBound) <= 0;
    }

    protected boolean isIntegerType(Class type) {
        if (double.class == type || float.class == type || Double.class == type || Float.class == type
                || char.class == type || Character.class == type) {
            return false;
        }

        return true;
    }

    /**
     * Converts the input as a number using java's number formatter to a string output.
     */
    private String doConvertFromNumberToString(Map<String, Object> context, Object value, Class toType) {
        // XW-409: If the input is a Number we should format it to a string using the choosen locale and use java's numberformatter
        if (Number.class.isAssignableFrom(toType)) {
            NumberFormat numFormat = NumberFormat.getInstance(getLocale(context));
            if (isIntegerType(toType)) {
                numFormat.setParseIntegerOnly(true);
            }
            numFormat.setGroupingUsed(true);
            numFormat.setMaximumFractionDigits(99); // to be sure we include all digits after decimal seperator, otherwise some of the fractions can be chopped

            String number = numFormat.format(value);
            if (number != null) {
                return number;
            }
        }

        return null; // no number
    }


    private String doConvertToString(Map<String, Object> context, Object value) {
        String result = null;

        if (value instanceof int[]) {
            int[] x = (int[]) value;
            List<Integer> intArray = new ArrayList(x.length);

            for (int aX : x) {
                intArray.add(Integer.valueOf(aX));
            }

            result = StringUtils.join(intArray, ", ");
        } else if (value instanceof long[]) {
            long[] x = (long[]) value;
            List<Long> longArray = new ArrayList(x.length);

            for (long aX : x) {
                longArray.add(Long.valueOf(aX));
            }

            result = StringUtils.join(longArray, ", ");
        } else if (value instanceof double[]) {
            double[] x = (double[]) value;
            List<Double> doubleArray = new ArrayList(x.length);

            for (double aX : x) {
                doubleArray.add(new Double(aX));
            }

            result = StringUtils.join(doubleArray, ", ");
        } else if (value instanceof boolean[]) {
            boolean[] x = (boolean[]) value;
            List<Boolean> booleanArray = new ArrayList(x.length);

            for (boolean aX : x) {
                booleanArray.add(new Boolean(aX));
            }

            result = StringUtils.join(booleanArray, ", ");
        } else if (value instanceof Date) {
            DateFormat df = null;
            if (value instanceof java.sql.Time) {
                df = DateFormat.getTimeInstance(DateFormat.MEDIUM, getLocale(context));
            } else if (value instanceof java.sql.Timestamp) {
                SimpleDateFormat dfmt = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT,
                        DateFormat.MEDIUM,
                        getLocale(context));
                df = new SimpleDateFormat(dfmt.toPattern() + MILLISECOND_FORMAT);
            } else {
                df = DateFormat.getDateInstance(DateFormat.SHORT, getLocale(context));
            }
            result = df.format(value);
        } else if (value instanceof String[]) {
            result = StringUtils.join((String[]) value, ", ");
        }

        return result;
    }
}

Other Struts examples (source code examples)

Here is a short list of links related to this Struts XWorkBasicConverter.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.