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     */
017    package org.apache.camel.impl.converter;
018    
019    import java.beans.PropertyEditor;
020    import java.beans.PropertyEditorManager;
021    import java.util.HashMap;
022    import java.util.Map;
023    
024    import org.apache.camel.Exchange;
025    import org.apache.camel.TypeConverter;
026    import org.apache.camel.util.LRUSoftCache;
027    import org.apache.camel.util.ObjectHelper;
028    import org.slf4j.Logger;
029    import org.slf4j.LoggerFactory;
030    
031    /**
032     * Uses the {@link java.beans.PropertyEditor} conversion system to convert Objects to
033     * and from String values.
034     *
035     * @deprecated should be removed as it can cause side-effects when using 3rd party property editors
036     *
037     * @version 
038     */
039    @Deprecated
040    public class PropertyEditorTypeConverter implements TypeConverter {
041    
042        private static final Logger LOG = LoggerFactory.getLogger(PropertyEditorTypeConverter.class);
043        // use a soft bound cache to avoid using too much memory in case a lot of different classes
044        // is being converted to string
045        private final Map<Class<?>, Class<?>> misses = new LRUSoftCache<Class<?>, Class<?>>(1000);
046        // we don't anticipate so many property editors so we have unbounded map
047        private final Map<Class<?>, PropertyEditor> cache = new HashMap<Class<?>, PropertyEditor>();
048    
049        public void clear() {
050            cache.clear();
051            misses.clear();
052        }
053    
054        @Override
055        public boolean allowNull() {
056            return false;
057        }
058    
059        @Override
060        public <T> T convertTo(Class<T> type, Object value) {
061            // We can't convert null values since we can't figure out a property
062            // editor for it.
063            if (value == null) {
064                return null;
065            }
066    
067            if (value.getClass() == String.class) {
068                // No conversion needed.
069                if (type == String.class) {
070                    return ObjectHelper.cast(type, value);
071                }
072    
073                Class<?> key = type;
074                PropertyEditor editor = lookupEditor(key);
075                if (editor != null) {
076                    // we are essentially not thread safe as we use 2 calls to convert
077                    editor.setAsText(value.toString());
078                    return ObjectHelper.cast(type, editor.getValue());
079                }
080            } else if (type == String.class) {
081                Class<?> key = value.getClass();
082                PropertyEditor editor = lookupEditor(key);
083                if (editor != null) {
084                    // we are essentially not thread safe as we use 2 calls to convert
085                    editor.setValue(value);
086                    return ObjectHelper.cast(type, editor.getAsText());
087                }
088            }
089    
090            return null;
091        }
092    
093        private PropertyEditor lookupEditor(Class<?> type) {
094            // check misses first
095            if (misses.containsKey(type)) {
096                LOG.trace("No previously found property editor for type: {}", type);
097                return null;
098            }
099    
100            synchronized (cache) {
101                // not a miss then try to lookup the editor
102                PropertyEditor editor = cache.get(type);
103                if (editor == null) {
104                    // findEditor is synchronized and very slow so we want to only lookup once for a given key
105                    // and then we use our own local cache for faster lookup
106                    editor = PropertyEditorManager.findEditor(type);
107    
108                    // either we found an editor, or if not then register it as a miss
109                    if (editor != null) {
110                        LOG.trace("Found property editor for type: {} -> {}", type, editor);
111                        cache.put(type, editor);
112                    } else {
113                        LOG.trace("Cannot find property editor for type: {}", type);
114                        misses.put(type, type);
115                    }
116                }
117                return editor;
118            }
119        }
120    
121        @Override
122        public <T> T convertTo(Class<T> type, Exchange exchange, Object value) {
123            return convertTo(type, value);
124        }
125    
126        @Override
127        public <T> T mandatoryConvertTo(Class<T> type, Object value) {
128            return convertTo(type, value);
129        }
130    
131        @Override
132        public <T> T mandatoryConvertTo(Class<T> type, Exchange exchange, Object value) {
133            return convertTo(type, value);
134        }
135    
136        @Override
137        public <T> T tryConvertTo(Class<T> type, Exchange exchange, Object value) {
138            try {
139                return convertTo(type, exchange, value);
140            } catch (Exception e) {
141                return null;
142            }
143        }
144    
145        @Override
146        public <T> T tryConvertTo(Class<T> type, Object value) {
147            try {
148                return convertTo(type, null, value);
149            } catch (Exception e) {
150                return null;
151            }
152        }
153    }