2 * Copyright 2000-2018 Vaadin Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
16 package com.vaadin.v7.data.util.converter;
18 import java.io.Serializable;
19 import java.lang.reflect.Modifier;
20 import java.util.ArrayList;
21 import java.util.Collection;
22 import java.util.HashSet;
23 import java.util.Locale;
26 * A converter that converts from {@link String} to {@link Collection} of tokens
29 * Allows to break a string into tokens using delimiter. Each token can be
30 * converted to its own model using provided converter.
32 * Default constructor uses <code>", "</code> as delimiter string and
33 * {@link String} for token types. Other constructors allow to configure
34 * delimiter and token types.
40 * @deprecated As of 8.0, a lightweight lambda-based converter can be build with
41 * {@link com.vaadin.data.Binder
42 * Binder}{@code .forField(...).withConverter(...)} methods.
45 public class StringToCollectionConverter
46 implements Converter<String, Collection> {
48 private final String delimiter;
49 private final Converter<String, ?> tokenConverter;
50 private final Class<?> tokenType;
51 private final CollectionFactory factory;
54 * Creates converter with <code>", "</code> as delimiter and {@link String}
55 * as token model type in collection.
57 public StringToCollectionConverter() {
58 this(", ", null, String.class);
62 * Creates converter with given {@code delimiter} and {@link String} as
63 * token model type in collection.
68 public StringToCollectionConverter(String delimiter) {
69 this(delimiter, null, String.class);
73 * Creates converter with given {@code tokenConverter} for convert tokens
74 * and expected {@code tokenType}.
76 * If {@code tokenConverter} is null then no conversation is done and
77 * {@link String} is used as token type in resulting model collection.
79 * @param tokenConverter
82 * expected token model type
84 public StringToCollectionConverter(Converter<String, ?> tokenConverter,
86 this(", ", tokenConverter, tokenType);
90 * Creates converter with given {@code tokenConverter} for convert tokens
91 * and expected {@code tokenType}.
93 * If {@code tokenConverter} is null then no conversation is done and
94 * {@link String} is used as token type in resulting model collection.
96 * @param tokenConverter
99 * expected token model type
101 * delimiter in presentation string
103 public StringToCollectionConverter(String delimiter,
104 Converter<String, ?> tokenConverter, Class<?> tokenClass) {
105 this(delimiter, tokenConverter, tokenClass,
106 new DefaultCollectionFactory());
110 * Creates converter with given {@code tokenConverter} for convert tokens
111 * and expected {@code tokenType}.
113 * If {@code tokenConverter} is null then no conversation is done and
114 * {@link String} is used as token type in resulting model collection.
116 * @param tokenConverter
117 * converter for token
119 * expected token model type
121 * delimiter in presentation string
123 * factory to create resulting collection
125 public StringToCollectionConverter(String delimiter,
126 Converter<String, ?> tokenConverter, Class<?> tokenClass,
127 CollectionFactory factory) {
128 if (delimiter == null || delimiter.isEmpty()) {
129 throw new IllegalArgumentException(
130 "Delimiter should be non-empty string");
132 this.delimiter = delimiter;
133 this.tokenConverter = tokenConverter;
134 tokenType = tokenClass;
135 this.factory = factory;
139 public Class<Collection> getModelType() {
140 return Collection.class;
144 public Class<String> getPresentationType() {
149 public Collection convertToModel(String value,
150 Class<? extends Collection> targetType, Locale locale)
151 throws Converter.ConversionException {
156 int index = value.indexOf(delimiter);
158 Collection result = factory.createCollection(targetType);
159 Converter converter = tokenConverter;
160 while (index != -1) {
161 collectToken(value.substring(previous, index), result, converter,
163 previous = index + delimiter.length();
164 index = value.indexOf(delimiter, previous);
166 collectToken(value.substring(previous), result, converter, locale);
171 public String convertToPresentation(Collection value,
172 Class<? extends String> targetType, Locale locale)
173 throws Converter.ConversionException {
177 StringBuilder builder = new StringBuilder();
178 Converter converter = tokenConverter;
179 for (Object o : value) {
180 if (converter == null) {
184 converter.convertToPresentation(o, targetType, locale));
186 builder.append(delimiter);
188 if (builder.length() != 0) {
189 return builder.substring(0, builder.length() - delimiter.length());
191 return builder.toString();
195 private void collectToken(String token, Collection collection,
196 Converter converter, Locale locale) {
197 if (converter == null) {
198 collection.add(token);
200 collection.add(converter.convertToModel(token, tokenType, locale));
205 * Default collection factory implementation.
210 public static class DefaultCollectionFactory implements CollectionFactory {
213 public Collection<?> createCollection(
214 Class<? extends Collection> type) {
215 if (type.isAssignableFrom(ArrayList.class)) {
216 return new ArrayList<Object>();
217 } else if (type.isAssignableFrom(HashSet.class)) {
218 return new HashSet<Object>();
219 } else if (!type.isInterface()
220 && !Modifier.isAbstract(type.getModifiers())) {
222 return type.newInstance();
223 } catch (InstantiationException ignore) {
224 } catch (IllegalAccessException ignore) {
227 return new ArrayList<Object>();
233 * Collection factory. Defines a strategy to create collection by collection
239 public interface CollectionFactory extends Serializable {
242 * Create collection by its {@code type}.
246 * @return instantiated collection with given {@code type}
248 Collection<?> createCollection(Class<? extends Collection> type);