Skip to content

Commit

Permalink
标识 com.feilong.context.converter.StringToBeanConverter接口
Browse files Browse the repository at this point in the history
@FunctionalInterface fix #741

com.feilong.context.converter.StringToBeanConverter接口移动到 feilong-core包
路径保持不变 fix #740

com.feilong.core.lang.StringUtil.toSingleValueMap(String, Class<T>,
Class<V>) 要支持定制转换value类 fix #738
  • Loading branch information
venusdrogon committed Sep 28, 2024
1 parent a203683 commit c26f5bb
Show file tree
Hide file tree
Showing 6 changed files with 417 additions and 106 deletions.
92 changes: 47 additions & 45 deletions ...text/converter/StringToBeanConverter.java → ...text/converter/StringToBeanConverter.java
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,45 +1,47 @@
/*
* Copyright (C) 2008 feilong
*
* 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.feilong.context.converter;

/**
* 将字符串转成 bean 的转换器.
*
* <p>
* 功能和{@link org.apache.commons.collections4.Transformer} 类似,但是更专业和具体
* </p>
*
* @author <a href="https://github.com/ifeilong/feilong">feilong</a>
* @param <T>
* the generic type
* @see org.apache.commons.collections4.Transformer
* @see "org.springframework.core.convert.converter.Converter"
* @see "org.springframework.core.convert.support.StringToEnumConverterFactory"
* @since 1.8.3
* @since 1.11.2 rename from AbstractParse
*/
public interface StringToBeanConverter<T> {

/**
* 转换.
*
* @param value
* the value
* @return 如果 <code>value</code> 是null或者empty,返回 null<br>
*/
T convert(String value);

}
/*
* Copyright (C) 2008 feilong
*
* 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.feilong.context.converter;

/**
* 将字符串转成 bean 的转换器.
*
* <p>
* 功能和{@link org.apache.commons.collections4.Transformer} 类似,但是更专业和具体
* </p>
*
* @author <a href="https://github.com/ifeilong/feilong">feilong</a>
* @param <T>
* the generic type
* @see org.apache.commons.collections4.Transformer
* @see "org.springframework.core.convert.converter.Converter"
* @see "org.springframework.core.convert.support.StringToEnumConverterFactory"
* @since 1.8.3
* @since 1.11.2 rename from AbstractParse
* @since 4.1.2 move from feilong-context
*/
@FunctionalInterface
public interface StringToBeanConverter<T> {

/**
* 转换.
*
* @param value
* the value
* @return 如果 <code>value</code> 是null或者empty,返回 null<br>
*/
T convert(String value);

}
172 changes: 112 additions & 60 deletions feilong-core/src/main/java/com/feilong/core/lang/StringUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.slf4j.helpers.FormattingTuple;
import org.slf4j.helpers.MessageFormatter;

import com.feilong.context.converter.StringToBeanConverter;
import com.feilong.core.CharsetType;
import com.feilong.core.Validate;
import com.feilong.core.bean.ConvertUtil;
Expand Down Expand Up @@ -1172,6 +1173,8 @@ public static <T> boolean tokenizeToArrayContains(String config,String delimiter
return false;
}

//---------------------------------------------------------------

/**
* 将 189=988;200=455;这种格式的字符串转换成map , map的key 是189这种, value 是988,455 这种等号后面的值,使用逗号分隔成list.
*
Expand All @@ -1195,15 +1198,15 @@ public static <T> boolean tokenizeToArrayContains(String config,String delimiter
*
* </blockquote>
*
* @param config
* @param configString
* 189=988;200=455; 这种格式的配置字符串, 用分号分隔一组, 等号分隔key 和value
* @return 如果 <code>config</code> 是null,返回 emptyMap() <br>
* 如果 <code>config</code> 是empty,返回 emptyMap()<br>
* @return 如果 <code>configString</code> 是null,返回 emptyMap() <br>
* 如果 <code>configString</code> 是empty,返回 emptyMap()<br>
* @since 3.3.4
* @apiNote 自动去除空格,忽略空
*/
public static Map<String, String> toSingleValueMap(String config){
return toSingleValueMap(config, String.class, String.class);
public static Map<String, String> toSingleValueMap(String configString){
return toSingleValueMap(configString, String.class, String.class);
}

/**
Expand Down Expand Up @@ -1232,50 +1235,130 @@ public static Map<String, String> toSingleValueMap(String config){
* the generic type
* @param <V>
* the value type
* @param config
* @param configString
* 189=988;200=455; 这种格式的配置字符串, 用分号分隔一组, 等号分隔key 和value
* @param keyClass
* key转换的类型,比如上面的背景中, 189 可以转换成String Long Integer
* @param valueElementClass
* value转换的类型,比如上面的背景中, 455 可以转换成String Long Integer
* @return 如果 <code>config</code> 是null,返回 emptyMap() <br>
* 如果 <code>config</code> 是empty,返回 emptyMap()<br>
* @return 如果 <code>configString</code> 是null,返回 emptyMap() <br>
* 如果 <code>configString</code> 是empty,返回 emptyMap()<br>
* 如果 <code>keyClass</code> 是null,抛出 {@link NullPointerException}<br>
* 如果 <code>valueElementClass</code> 是null,抛出 {@link NullPointerException}<br>
* @since 3.3.4
* @apiNote 自动去除空格,忽略空
*/
public static <T, V> Map<T, V> toSingleValueMap(String config,Class<T> keyClass,Class<V> valueElementClass){
public static <T, V> Map<T, V> toSingleValueMap(String configString,Class<T> keyClass,Class<V> valueElementClass){
return toMap(configString, keyClass, (valueString) -> {
return convert(valueString, valueElementClass);
});
}

if (isNullOrEmpty(config)){
/**
* 将 73034693=0-50;11487680=0-43;51099626=0-50; 这种格式的字符串转换成map.
*
* <p>
* map的key 是73034693这种, value 可以TrackQueryExtendParam对象
*
* <pre class="code">
* public class TrackQueryExtendParam{
*
* // 单集编号 最小.
* private Integer minEpisodeNumber;
*
* // 单集编号 最大.
* private Integer maxEpisodeNumber;
*
* //setter/getter 省略
* }
* </pre>
* </p>
*
* <h3>解析代码示例:</h3>
*
* <blockquote>
*
* <pre class="code">
*
* String configString = "73034693=0-50;\n"//
* + "11487680=0-43;\n"//
* + "51099626=0-50;";
*
* Map{@code <Long, TrackQueryExtendParam>} map = StringUtil.toMap(configString, Long.class, (valueString) -> {
* String[] albumQueryParamsArray = StringUtil.tokenizeToStringArray(valueString, "-");
* if (isNullOrEmpty(albumQueryParamsArray)){
* return null;
* }
* try{
* //只有1个
* if (1 == size(albumQueryParamsArray)){
* //默认 0-x
* Integer max = toInteger(albumQueryParamsArray[0]);
* return new TrackQueryExtendParam(0, max);
* }
*
* Integer min = toInteger(albumQueryParamsArray[0]);
* Integer max = toInteger(albumQueryParamsArray[1]);
* return new TrackQueryExtendParam(min, max);
*
* }catch (Exception e){
* return null;
* }
* });
*
* </pre>
*
* </blockquote>
*
* @param <T>
* the generic type
* @param <V>
* the value type
* @param configString
* 73034693=0-50;11487680=0-43;51099626=0-50; 这种格式的配置字符串, 用分号分隔一组, 等号分隔key 和value
* @param keyClass
* key转换的类型,比如上面的背景中, 73034693 可以转换成String Long Integer
* @param valueStringToBeanConverter
* value转换的类型
* @return 如果 <code>configString</code> 是null,返回 emptyMap() <br>
* 如果 <code>configString</code> 是empty,返回 emptyMap()<br>
* 如果 <code>keyClass</code> 是null,抛出 {@link NullPointerException}<br>
* 如果 <code>stringToBeanConverter</code> 是null,抛出 {@link NullPointerException}<br>
* @since 4.1.2
* @apiNote 自动去除空格,忽略空
*/
public static <T, V> Map<T, V> toMap(String configString,Class<T> keyClass,StringToBeanConverter<V> valueStringToBeanConverter){
if (isNullOrEmpty(configString)){
return emptyMap();
}

Validate.notNull(keyClass, "keyClass can't be null!");
Validate.notNull(valueElementClass, "valueElementClass can't be null!");
//entry之间的分隔符
String entryDelimiters = ";";
//key 和value之间的分隔符
String keyAndValueDelimiters = "=";

//---------------------------------------------------------------

String[] entrys = StringUtil.tokenizeToStringArray(config, ";");
String[] entrys = StringUtil.tokenizeToStringArray(configString, entryDelimiters);
if (isNullOrEmpty(entrys)){
return emptyMap();
}
//---------------------------------------------------------------
Validate.notNull(keyClass, "keyClass can't be null!");
Validate.notNull(valueStringToBeanConverter, "stringToBeanConverter can't be null!");

//---------------------------------------------------------------
Map<T, V> map = newHashMap();
for (String keyAndValueString : entrys){
if (isNullOrEmpty(keyAndValueString)){
continue;
}

String[] keyAndValues = StringUtil.tokenizeToStringArray(keyAndValueString, "=");
String[] keyAndValues = StringUtil.tokenizeToStringArray(keyAndValueString, keyAndValueDelimiters);
if (size(keyAndValues) != 2){
continue;
}

//---------------------------------------------------------------
map.put(
convert(keyAndValues[0], keyClass), //
convert(keyAndValues[1], valueElementClass));
T key = ConvertUtil.convert(keyAndValues[0], keyClass);
V value = valueStringToBeanConverter.convert(keyAndValues[1]);
map.put(key, value);
}
return map;
}
Expand Down Expand Up @@ -1306,55 +1389,24 @@ public static <T, V> Map<T, V> toSingleValueMap(String config,Class<T> keyClass,
* the generic type
* @param <V>
* the value type
* @param config
* @param configString
* 189=988,900;200=455; 这种格式的配置字符串, 用分号分隔一组, 等号分隔key 和value
* @param keyClass
* key转换的类型,比如上面的背景中, 189 可以转换成String Long Integer
* @param valueElementClass
* value转换的类型,比如上面的背景中, 455 可以转换成String Long Integer
* @return 如果 <code>config</code> 是null,返回 emptyMap() <br>
* 如果 <code>config</code> 是empty,返回 emptyMap()<br>
* @return 如果 <code>configString</code> 是null,返回 emptyMap() <br>
* 如果 <code>configString</code> 是empty,返回 emptyMap()<br>
* 如果 <code>keyClass</code> 是null,抛出 {@link NullPointerException}<br>
* 如果 <code>valueElementClass</code> 是null,抛出 {@link NullPointerException}<br>
* @since 3.3.4
* @apiNote 自动去除空格,忽略空
*/
public static <T, V> Map<T, List<V>> toMultiValueMap(String config,Class<T> keyClass,Class<V> valueElementClass){
if (isNullOrEmpty(config)){
return emptyMap();
}

Validate.notNull(keyClass, "keyClass can't be null!");
Validate.notNull(valueElementClass, "valueElementClass can't be null!");

//---------------------------------------------------------------
String[] entrys = tokenizeToStringArray(config, ";");
if (isNullOrEmpty(entrys)){
return emptyMap();
}

//---------------------------------------------------------------

Map<T, List<V>> map = newHashMap();
for (String entry : entrys){
if (isNullOrEmpty(entry)){
continue;
}

String[] keyAndValuesMapping = tokenizeToStringArray(entry, "=");
if (size(keyAndValuesMapping) != 2){
continue;
}

//---------------------------------------------------------------
T key = convert(keyAndValuesMapping[0], keyClass);

String[] values = StringUtil.tokenizeToStringArray(keyAndValuesMapping[1], ",");
List<V> valueList = toList(toArray(values, valueElementClass));

map.put(key, valueList);
}
return map;
public static <T, V> Map<T, List<V>> toMultiValueMap(String configString,Class<T> keyClass,Class<V> valueElementClass){
return toMap(configString, keyClass, (valueString) -> {
String[] values = StringUtil.tokenizeToStringArray(valueString, ",");
return toList(toArray(values, valueElementClass));
});
}

// [start]format
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
ToSingleValueMapTest.class,
ToSingleValueMapConvertTest.class,
ToMultiValueMapTest.class,
ToMapConvertTest.class,
//
})
public class StringUtilSuiteTests{
Expand Down
Loading

0 comments on commit c26f5bb

Please sign in to comment.