/* * 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.wicket; import java.lang.ref.WeakReference; import java.math.BigDecimal; import java.math.BigInteger; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.Locale; import java.util.Map; import org.apache.wicket.util.convert.ConversionException; import org.apache.wicket.util.convert.IConverter; import org.apache.wicket.util.convert.converter.BigDecimalConverter; import org.apache.wicket.util.convert.converter.BigIntegerConverter; import org.apache.wicket.util.convert.converter.BooleanConverter; import org.apache.wicket.util.convert.converter.ByteConverter; import org.apache.wicket.util.convert.converter.CalendarConverter; import org.apache.wicket.util.convert.converter.CharacterConverter; import org.apache.wicket.util.convert.converter.DateConverter; import org.apache.wicket.util.convert.converter.DoubleConverter; import org.apache.wicket.util.convert.converter.FloatConverter; import org.apache.wicket.util.convert.converter.IntegerConverter; import org.apache.wicket.util.convert.converter.LocalDateConverter; import org.apache.wicket.util.convert.converter.LocalDateTimeConverter; import org.apache.wicket.util.convert.converter.LocalTimeConverter; import org.apache.wicket.util.convert.converter.LongConverter; import org.apache.wicket.util.convert.converter.ShortConverter; import org.apache.wicket.util.convert.converter.SqlDateConverter; import org.apache.wicket.util.convert.converter.SqlTimeConverter; import org.apache.wicket.util.convert.converter.SqlTimestampConverter; import org.apache.wicket.util.lang.Args; import org.apache.wicket.util.lang.Objects; /** * Implementation of {@link IConverterLocator} interface, which locates converters for a given type. * It serves as a registry for {@link IConverter} instances stored by type, and is the default * locator for Wicket. * * @see IConverterLocator * @author Eelco Hillenius * @author Jonathan Locke * */ public class ConverterLocator implements IConverterLocator { /** * ConverterLocator that is to be used when no registered converter is found. * * @param <C> * The object to convert from and to String */ private static class DefaultConverter<C> implements IConverter<C> { private static final long serialVersionUID = 1L; private final transient WeakReference<Class<C>> type; /** * Construct. * * @param type */ private DefaultConverter(Class<C> type) { this.type = new WeakReference<>(type); } @Override public C convertToObject(String value, Locale locale) { if (value == null) { return null; } Class<C> theType = type.get(); if ("".equals(value)) { if (String.class.equals(theType)) { return theType.cast(""); } return null; } try { C converted = Objects.convertValue(value, theType); if (converted != null) { return converted; } if (theType != null && theType.isInstance(value)) { return theType.cast(value); } } catch (Exception e) { throw new ConversionException(e.getMessage(), e).setSourceValue(value); } throw new ConversionException("Could not convert value: " + value + " to type: " + theType.getName() + ". Could not find compatible converter.").setSourceValue(value); } @Override public String convertToString(C value, Locale locale) { if (value == null || "".equals(value)) { return ""; } try { return Objects.convertValue(value, String.class); } catch (RuntimeException e) { throw new ConversionException("Could not convert object of type: " + value.getClass() + " to String. Possible its #toString() returned null. " + "Either install a custom converter (see IConverterLocator) or " + "override #toString() to return a non-null value.", e).setSourceValue(value) .setConverter(this); } } } private static final long serialVersionUID = 1L; /** Maps Classes to ITypeConverters. */ private final Map<String, IConverter<?>> classToConverter = new HashMap<>(); /** * Constructor */ public ConverterLocator() { set(Boolean.TYPE, BooleanConverter.INSTANCE); set(Boolean.class, BooleanConverter.INSTANCE); set(Byte.TYPE, ByteConverter.INSTANCE); set(Byte.class, ByteConverter.INSTANCE); set(Character.TYPE, CharacterConverter.INSTANCE); set(Character.class, CharacterConverter.INSTANCE); set(Double.TYPE, DoubleConverter.INSTANCE); set(Double.class, DoubleConverter.INSTANCE); set(Float.TYPE, FloatConverter.INSTANCE); set(Float.class, FloatConverter.INSTANCE); set(Integer.TYPE, IntegerConverter.INSTANCE); set(Integer.class, IntegerConverter.INSTANCE); set(Long.TYPE, LongConverter.INSTANCE); set(Long.class, LongConverter.INSTANCE); set(Short.TYPE, ShortConverter.INSTANCE); set(Short.class, ShortConverter.INSTANCE); set(BigDecimal.class, new BigDecimalConverter()); set(BigInteger.class, new BigIntegerConverter()); set(Date.class, new DateConverter()); set(java.sql.Date.class, new SqlDateConverter()); set(java.sql.Time.class, new SqlTimeConverter()); set(java.sql.Timestamp.class, new SqlTimestampConverter()); set(Calendar.class, new CalendarConverter()); set(LocalDate.class, new LocalDateConverter()); set(LocalDateTime.class, new LocalDateTimeConverter()); set(LocalTime.class, new LocalTimeConverter()); } /** * Gets the type converter that is registered for class c. * * @param <C> * The object to convert from and to String * @param c * The class to get the type converter for * @return The type converter that is registered for class c or null if no type converter was * registered for class c */ public final <C> IConverter<C> get(Class<C> c) { return (IConverter<C>) classToConverter.get(c.getName()); } /** * Converts the given value to class c. * * @param type * Class to get the converter for. * * @return The converter for the given type * * @see org.apache.wicket.util.convert.IConverter#convertToObject(String, java.util.Locale) */ @Override public final <C> IConverter<C> getConverter(Class<C> type) { // Null is always converted to null if (type == null) { @SuppressWarnings("unchecked") IConverter<C> converter = (IConverter<C>)new DefaultConverter<String>(String.class); return converter; } // Get type converter for class final IConverter<C> converter = get(type); if (converter == null) { return new DefaultConverter<>(type); } return converter; } /** * Removes the type converter currently registered for class c. * * @param c * The class for which the converter registration should be removed * @return The converter that was registered for class c before removal or null if none was * registered */ public final IConverter<?> remove(Class<?> c) { return classToConverter.remove(c.getName()); } /** * Registers a converter for use with class c. * * @param converter * The converter to add * @param c * The class for which the converter should be used * @return The previous registered converter for class c or null if none was registered yet for * class c */ public final IConverter<?> set(final Class<?> c, final IConverter<?> converter) { Args.notNull(c, "Class"); Args.notNull(converter, "converter"); return classToConverter.put(c.getName(), converter); } }