001/*
002 * Copyright 2002-2014 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.beans.propertyeditors;
018
019import java.beans.PropertyEditorSupport;
020
021import org.springframework.util.StringUtils;
022
023/**
024 * Editor for a {@link Character}, to populate a property
025 * of type {@code Character} or {@code char} from a String value.
026 *
027 * <p>Note that the JDK does not contain a default
028 * {@link java.beans.PropertyEditor property editor} for {@code char}!
029 * {@link org.springframework.beans.BeanWrapperImpl} will register this
030 * editor by default.
031 *
032 * <p>Also supports conversion from a Unicode character sequence; e.g.
033 * {@code u0041} ('A').
034 *
035 * @author Juergen Hoeller
036 * @author Rob Harrop
037 * @author Rick Evans
038 * @since 1.2
039 * @see Character
040 * @see org.springframework.beans.BeanWrapperImpl
041 */
042public class CharacterEditor extends PropertyEditorSupport {
043
044        /**
045         * The prefix that identifies a string as being a Unicode character sequence.
046         */
047        private static final String UNICODE_PREFIX = "\\u";
048
049        /**
050         * The length of a Unicode character sequence.
051         */
052        private static final int UNICODE_LENGTH = 6;
053
054
055        private final boolean allowEmpty;
056
057
058        /**
059         * Create a new CharacterEditor instance.
060         * <p>The "allowEmpty" parameter controls whether an empty String is to be
061         * allowed in parsing, i.e. be interpreted as the {@code null} value when
062         * {@link #setAsText(String) text is being converted}. If {@code false},
063         * an {@link IllegalArgumentException} will be thrown at that time.
064         * @param allowEmpty if empty strings are to be allowed
065         */
066        public CharacterEditor(boolean allowEmpty) {
067                this.allowEmpty = allowEmpty;
068        }
069
070
071        @Override
072        public void setAsText(String text) throws IllegalArgumentException {
073                if (this.allowEmpty && !StringUtils.hasLength(text)) {
074                        // Treat empty String as null value.
075                        setValue(null);
076                }
077                else if (text == null) {
078                        throw new IllegalArgumentException("null String cannot be converted to char type");
079                }
080                else if (isUnicodeCharacterSequence(text)) {
081                        setAsUnicode(text);
082                }
083                else if (text.length() == 1) {
084                        setValue(Character.valueOf(text.charAt(0)));
085                }
086                else {
087                        throw new IllegalArgumentException("String [" + text + "] with length " +
088                                        text.length() + " cannot be converted to char type: neither Unicode nor single character");
089                }
090        }
091
092        @Override
093        public String getAsText() {
094                Object value = getValue();
095                return (value != null ? value.toString() : "");
096        }
097
098
099        private boolean isUnicodeCharacterSequence(String sequence) {
100                return (sequence.startsWith(UNICODE_PREFIX) && sequence.length() == UNICODE_LENGTH);
101        }
102
103        private void setAsUnicode(String text) {
104                int code = Integer.parseInt(text.substring(UNICODE_PREFIX.length()), 16);
105                setValue(Character.valueOf((char) code));
106        }
107
108}