diff options
author | Denis Anisimov <denis@vaadin.com> | 2015-01-08 16:01:48 +0200 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2015-01-15 14:05:02 +0000 |
commit | 69cd990c9b83851a959a7d3f5b88138283f3e500 (patch) | |
tree | 74957d6411175ae5c336a085c34dc3d15851db48 /server/src/com/vaadin/data/util | |
parent | 8289b4ab95850000a3e28e0b66bf20cb5a03f895 (diff) | |
download | vaadin-framework-69cd990c9b83851a959a7d3f5b88138283f3e500.tar.gz vaadin-framework-69cd990c9b83851a959a7d3f5b88138283f3e500.zip |
StringToCollectionConverter class implementation (#15464).
Change-Id: I563f4403d6b6f7658f195ef97d3db05838e257af
Diffstat (limited to 'server/src/com/vaadin/data/util')
-rw-r--r-- | server/src/com/vaadin/data/util/converter/StringToCollectionConverter.java | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/server/src/com/vaadin/data/util/converter/StringToCollectionConverter.java b/server/src/com/vaadin/data/util/converter/StringToCollectionConverter.java new file mode 100644 index 0000000000..a84a3575f7 --- /dev/null +++ b/server/src/com/vaadin/data/util/converter/StringToCollectionConverter.java @@ -0,0 +1,236 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * 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.vaadin.data.util.converter; + +import java.io.Serializable; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Locale; + +/** + * A converter that converts from {@link String} to {@link Collection} of tokens + * and back. + * <p> + * Allows to break a string into tokens using delimiter. Each token can be + * converted to its own model using provided converter. + * <p> + * Default constructor uses <code>", "</code> as delimiter string and + * {@link String} for token types. Other constructors allow to configure + * delimiter and token types. + * + * @author Vaadin Ltd + */ +public class StringToCollectionConverter implements + Converter<String, Collection> { + + private final String delimiter; + private final Converter<String, ?> tokenConverter; + private final Class<?> tokenType; + private final CollectionFactory factory; + + /** + * Creates converter with <code>", "</code> as delimiter and {@link String} + * as token model type in collection. + */ + public StringToCollectionConverter() { + this(", ", null, String.class); + } + + /** + * Creates converter with given {@code delimiter} and {@link String} as + * token model type in collection. + * + * @param delimiter + * custom delimiter + */ + public StringToCollectionConverter(String delimiter) { + this(delimiter, null, String.class); + } + + /** + * Creates converter with given {@code tokenConverter} for convert tokens + * and expected {@code tokenType}. + * <p> + * If {@code tokenConverter} is null then no conversation is done and + * {@link String} is used as token type in resulting model collection. + * + * @param tokenConverter + * converter for token + * @param tokenType + * expected token model type + */ + public StringToCollectionConverter(Converter<String, ?> tokenConverter, + Class<?> tokenType) { + this(", ", tokenConverter, tokenType); + } + + /** + * Creates converter with given {@code tokenConverter} for convert tokens + * and expected {@code tokenType}. + * <p> + * If {@code tokenConverter} is null then no conversation is done and + * {@link String} is used as token type in resulting model collection. + * + * @param tokenConverter + * converter for token + * @param tokenType + * expected token model type + * @param delimiter + * delimiter in presentation string + */ + public StringToCollectionConverter(String delimiter, + Converter<String, ?> tokenConverter, Class<?> tokenClass) { + this(delimiter, tokenConverter, tokenClass, + new DefaultCollectionFactory()); + } + + /** + * Creates converter with given {@code tokenConverter} for convert tokens + * and expected {@code tokenType}. + * <p> + * If {@code tokenConverter} is null then no conversation is done and + * {@link String} is used as token type in resulting model collection. + * + * @param tokenConverter + * converter for token + * @param tokenType + * expected token model type + * @param delimiter + * delimiter in presentation string + * @param factory + * factory to create resulting collection + */ + public StringToCollectionConverter(String delimiter, + Converter<String, ?> tokenConverter, Class<?> tokenClass, + CollectionFactory factory) { + if (delimiter == null || delimiter.isEmpty()) { + throw new IllegalArgumentException( + "Delimiter should be non-empty string"); + } + this.delimiter = delimiter; + this.tokenConverter = tokenConverter; + tokenType = tokenClass; + this.factory = factory; + } + + @Override + public Class<Collection> getModelType() { + return Collection.class; + } + + @Override + public Class<String> getPresentationType() { + return String.class; + } + + @Override + public Collection convertToModel(String value, + Class<? extends Collection> targetType, Locale locale) + throws Converter.ConversionException { + int index = value.indexOf(delimiter); + int previous = 0; + Collection result = factory.createCollection(targetType); + Converter converter = tokenConverter; + while (index != -1) { + collectToken(value.substring(previous, index), result, converter, + locale); + previous = index + delimiter.length(); + index = value.indexOf(delimiter, previous); + } + if (result.size() > 0) { + collectToken(value.substring(previous), result, converter, locale); + } + return result; + } + + @Override + public String convertToPresentation(Collection value, + Class<? extends String> targetType, Locale locale) + throws Converter.ConversionException { + StringBuilder builder = new StringBuilder(); + Converter converter = tokenConverter; + for (Iterator<?> iterator = value.iterator(); iterator.hasNext();) { + if (converter == null) { + builder.append(iterator.next()); + } else { + builder.append(converter.convertToPresentation(iterator.next(), + targetType, locale)); + } + builder.append(delimiter); + } + if (builder.length() > 0) { + return builder.substring(0, builder.length() - delimiter.length()); + } else { + return builder.toString(); + } + } + + private void collectToken(String token, Collection collection, + Converter converter, Locale locale) { + if (converter == null) { + collection.add(token); + } else { + collection.add(converter.convertToModel(token, tokenType, locale)); + } + } + + /** + * Default collection factory implementation. + * + * @author Vaadin Ltd + */ + public static class DefaultCollectionFactory implements CollectionFactory { + + @Override + public Collection<?> createCollection(Class<? extends Collection> type) { + if (type.isAssignableFrom(ArrayList.class)) { + return new ArrayList(); + } else if (type.isAssignableFrom(HashSet.class)) { + return new HashSet(); + } else if (!type.isInterface() + && !Modifier.isAbstract(type.getModifiers())) { + try { + return type.newInstance(); + } catch (InstantiationException ignore) { + } catch (IllegalAccessException ignore) { + } + } + return new ArrayList(); + } + + } + + /** + * Collection factory. Defines a strategy to create collection by collection + * class. + * + * @author Vaadin Ltd + */ + public interface CollectionFactory extends Serializable { + + /** + * Create collection by its {@code type}. + * + * @param type + * collection type + * @return instantiated collection with given {@code type} + */ + Collection<?> createCollection(Class<? extends Collection> type); + } +} |