001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.util.convert; 018 019import java.text.ParseException; 020import java.util.Locale; 021 022import javax.swing.text.MaskFormatter; 023 024import org.apache.wicket.util.lang.Args; 025 026 027/** 028 * A converter that takes a mask into account. It is specifically meant for overrides on individual 029 * components, that provide their own converter by returning it from 030 * {@code Component#getConverter(Class)}. It uses an instance of {@link MaskFormatter} to delegate 031 * the masking and unmasking to. 032 * <p> 033 * The following characters can be specified (adopted from the MaskFormatter documentation): 034 * 035 * <table border=1 summary="Valid characters and their descriptions"> 036 * <tr> 037 * <th>Character </th> 038 * <th> 039 * <p align="left"> 040 * Description 041 * </p> 042 * </th> 043 * </tr> 044 * <tr> 045 * <td>#</td> 046 * <td>Any valid number, uses <code>Character.isDigit</code>.</td> 047 * </tr> 048 * <tr> 049 * <td>'</td> 050 * <td>Escape character, used to escape any of the special formatting characters.</td> 051 * </tr> 052 * <tr> 053 * <td>U</td> 054 * <td>Any character (<code>Character.isLetter</code>). All lowercase letters are mapped to upper 055 * case.</td> 056 * </tr> 057 * <tr> 058 * <td>L</td> 059 * <td>Any character (<code>Character.isLetter</code>). All upper case letters are mapped to lower 060 * case.</td> 061 * </tr> 062 * <tr> 063 * <td>A</td> 064 * <td>Any character or number (<code>Character.isLetter</code> or <code>Character.isDigit</code>)</td> 065 * </tr> 066 * <tr> 067 * <td>?</td> 068 * <td>Any character (<code>Character.isLetter</code>).</td> 069 * </tr> 070 * <tr> 071 * <td></td> 072 * <td>Anything.</td> 073 * </tr> 074 * <tr> 075 * <td>H</td> 076 * <td>Any hex character (0-9, a-f or A-F).</td> 077 * </tr> 078 * </table> 079 * 080 * <p> 081 * Typically characters correspond to one char, but in certain languages this is not the case. The 082 * mask is on a per character basis, and will thus adjust to fit as many chars as are needed. 083 * </p> 084 * 085 * @see MaskFormatter 086 * 087 * @author Eelco Hillenius 088 * @param <C> 089 */ 090public class MaskConverter<C> implements IConverter<C> 091{ 092 private static final long serialVersionUID = 1L; 093 094 /** Object that knows all about masks. */ 095 private final MaskFormatter maskFormatter; 096 097 /** 098 * Construct. 099 * 100 * @param maskFormatter 101 * The mask formatter to use for masking and unmasking values 102 */ 103 public MaskConverter(final MaskFormatter maskFormatter) 104 { 105 Args.notNull(maskFormatter, "maskFormatter"); 106 107 this.maskFormatter = maskFormatter; 108 } 109 110 /** 111 * Construct; converts to Strings. 112 * 113 * @param mask 114 * The mask to use for this converter instance 115 * @see MaskFormatter 116 */ 117 public MaskConverter(final String mask) 118 { 119 this(mask, String.class); 120 } 121 122 /** 123 * Construct. 124 * 125 * @param mask 126 * The mask to use for this converter instance 127 * @param type 128 * The type to convert string values to. 129 * @see MaskFormatter 130 */ 131 public MaskConverter(final String mask, final Class<?> type) 132 { 133 try 134 { 135 maskFormatter = new MaskFormatter(mask); 136 maskFormatter.setValueClass(type); 137 maskFormatter.setAllowsInvalid(true); 138 maskFormatter.setValueContainsLiteralCharacters(true); 139 } 140 catch (ParseException e) 141 { 142 throw new RuntimeException(e); 143 } 144 } 145 146 /** 147 * Converts a string to an object using {@link MaskFormatter#stringToValue(String)}. 148 */ 149 @Override 150 @SuppressWarnings("unchecked") 151 public C convertToObject(final String value, final Locale locale) 152 { 153 try 154 { 155 return (C)maskFormatter.stringToValue(value); 156 } 157 catch (ParseException e) 158 { 159 throw new ConversionException(e); 160 } 161 } 162 163 /** 164 * Converts the value to a string using {@link MaskFormatter#valueToString(Object)}. 165 */ 166 @Override 167 public String convertToString(final C value, final Locale locale) 168 { 169 try 170 { 171 return maskFormatter.valueToString(value); 172 } 173 catch (ParseException e) 174 { 175 throw new ConversionException(e); 176 } 177 } 178}