Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
希川
container-mini
提交
ec71c6cd
C
container-mini
项目概览
希川
/
container-mini
通知
6
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
C
container-mini
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
ec71c6cd
编写于
11月 19, 2021
作者:
希川
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
<feat>: 属性转换
上级
a9925f1b
变更
12
隐藏空白更改
内联
并排
Showing
12 changed file
with
728 addition
and
0 deletion
+728
-0
src/main/java/cn/noexception/container/context/support/ConversionServiceFactoryBean.java
...ntainer/context/support/ConversionServiceFactoryBean.java
+71
-0
src/main/java/cn/noexception/container/factory/convert/ConversionService.java
...xception/container/factory/convert/ConversionService.java
+16
-0
src/main/java/cn/noexception/container/factory/convert/converter/Converter.java
...eption/container/factory/convert/converter/Converter.java
+12
-0
src/main/java/cn/noexception/container/factory/convert/converter/ConverterFactory.java
...container/factory/convert/converter/ConverterFactory.java
+12
-0
src/main/java/cn/noexception/container/factory/convert/converter/ConverterRegistry.java
...ontainer/factory/convert/converter/ConverterRegistry.java
+16
-0
src/main/java/cn/noexception/container/factory/convert/converter/GenericConverter.java
...container/factory/convert/converter/GenericConverter.java
+58
-0
src/main/java/cn/noexception/container/factory/convert/support/DefaultConversionService.java
...ner/factory/convert/support/DefaultConversionService.java
+20
-0
src/main/java/cn/noexception/container/factory/convert/support/GenericConversionService.java
...ner/factory/convert/support/GenericConversionService.java
+137
-0
src/main/java/cn/noexception/container/factory/convert/support/StringToNumberConverterFactory.java
...ctory/convert/support/StringToNumberConverterFactory.java
+35
-0
src/main/java/cn/noexception/container/factory/support/AbstractAutowiredCapableBeanFactory.java
.../factory/support/AbstractAutowiredCapableBeanFactory.java
+12
-0
src/main/java/cn/noexception/container/factory/support/AbstractBeanFactory.java
...eption/container/factory/support/AbstractBeanFactory.java
+11
-0
src/main/java/cn/noexception/container/factory/utils/NumberUtils.java
...a/cn/noexception/container/factory/utils/NumberUtils.java
+328
-0
未找到文件。
src/main/java/cn/noexception/container/context/support/ConversionServiceFactoryBean.java
0 → 100644
浏览文件 @
ec71c6cd
package
cn.noexception.container.context.support
;
import
cn.noexception.container.factory.FactoryBean
;
import
cn.noexception.container.factory.InitializingBean
;
import
cn.noexception.container.factory.convert.ConversionService
;
import
cn.noexception.container.factory.convert.converter.Converter
;
import
cn.noexception.container.factory.convert.converter.ConverterFactory
;
import
cn.noexception.container.factory.convert.converter.ConverterRegistry
;
import
cn.noexception.container.factory.convert.converter.GenericConverter
;
import
cn.noexception.container.factory.convert.support.DefaultConversionService
;
import
cn.noexception.container.factory.convert.support.GenericConversionService
;
import
jdk.internal.jline.internal.Nullable
;
import
java.util.Set
;
/**
* ConversionServiceFactoryBean
*
* @author 吕滔
* @Date 2021/11/19 16:21
*/
public
class
ConversionServiceFactoryBean
implements
FactoryBean
<
ConversionService
>,
InitializingBean
{
@Nullable
private
Set
<?>
converters
;
@Nullable
private
GenericConversionService
conversionService
;
@Override
public
ConversionService
getObject
()
throws
Exception
{
return
conversionService
;
}
@Override
public
Class
<?>
getObjectType
()
{
return
conversionService
.
getClass
();
}
@Override
public
boolean
isSingleton
()
{
return
true
;
}
@Override
public
void
afterPropertiesSet
()
throws
Exception
{
this
.
conversionService
=
new
DefaultConversionService
();
registerConversions
(
converters
,
conversionService
);
}
private
void
registerConversions
(
Set
<?>
converters
,
ConverterRegistry
registry
)
{
if
(
converters
!=
null
)
{
for
(
Object
converter
:
converters
)
{
if
(
converter
instanceof
GenericConverter
)
{
registry
.
addConverter
((
GenericConverter
)
converter
);
}
else
if
(
converter
instanceof
Converter
<?,
?>)
{
registry
.
addConverterFactory
((
ConverterFactory
<?,
?>)
converter
);
}
else
if
(
converter
instanceof
ConverterFactory
<?,
?>)
{
registry
.
addConverterFactory
((
ConverterFactory
<?,
?>)
converter
);
}
else
{
throw
new
IllegalArgumentException
(
"Each converter object must implememnt one of the "
+
"Converter, ConverterFactory, or GenericConverter interfaces"
);
}
}
}
}
public
void
setConverters
(
Set
<?>
converters
)
{
this
.
converters
=
converters
;
}
}
src/main/java/cn/noexception/container/factory/convert/ConversionService.java
0 → 100644
浏览文件 @
ec71c6cd
package
cn.noexception.container.factory.convert
;
import
jdk.internal.jline.internal.Nullable
;
/**
* ConversionService
*
* @author 吕滔
* @Date 2021/11/19 12:00
*/
public
interface
ConversionService
{
boolean
canConvert
(
@Nullable
Class
<?>
sourceType
,
Class
<?>
targetType
);
<
T
>
T
convert
(
Object
source
,
Class
<
T
>
targetType
);
}
src/main/java/cn/noexception/container/factory/convert/converter/Converter.java
0 → 100644
浏览文件 @
ec71c6cd
package
cn.noexception.container.factory.convert.converter
;
/**
* Converter
* 定义类型转换接口
*
* @author 吕滔
* @Date 2021/11/18 16:42
*/
public
interface
Converter
<
S
,
T
>
{
T
convert
(
S
source
);
}
src/main/java/cn/noexception/container/factory/convert/converter/ConverterFactory.java
0 → 100644
浏览文件 @
ec71c6cd
package
cn.noexception.container.factory.convert.converter
;
/**
* ConverterFactory
* 类型转换工厂
*
* @author 吕滔
* @Date 2021/11/18 16:43
*/
public
interface
ConverterFactory
<
S
,
R
>
{
<
T
extends
R
>
Converter
<
S
,
T
>
getConverter
(
Class
<
T
>
targetType
);
}
src/main/java/cn/noexception/container/factory/convert/converter/ConverterRegistry.java
0 → 100644
浏览文件 @
ec71c6cd
package
cn.noexception.container.factory.convert.converter
;
/**
* ConverterRegistry
* 类型转换注册接口
*
* @author 吕滔
* @Date 2021/11/18 16:45
*/
public
interface
ConverterRegistry
{
void
addConverter
(
Converter
<?,
?>
converter
);
void
addConverter
(
GenericConverter
converter
);
void
addConverterFactory
(
ConverterFactory
<?,
?>
converterFactory
);
}
src/main/java/cn/noexception/container/factory/convert/converter/GenericConverter.java
0 → 100644
浏览文件 @
ec71c6cd
package
cn.noexception.container.factory.convert.converter
;
import
cn.hutool.core.lang.Assert
;
import
java.util.Set
;
/**
* GenericConverter
*
* @author 吕滔
* @Date 2021/11/18 16:56
*/
public
interface
GenericConverter
{
Set
<
ConvertiblePair
>
getConvertibleTypes
();
Object
convert
(
Object
source
,
Class
sourceType
,
Class
targetType
);
final
class
ConvertiblePair
{
private
final
Class
<?>
sourceType
;
private
final
Class
<?>
targetType
;
public
ConvertiblePair
(
Class
<?>
sourceType
,
Class
<?>
targetType
)
{
Assert
.
notNull
(
sourceType
,
"来源类型不能为空。"
);
Assert
.
notNull
(
targetType
,
"目标类型不能为空。"
);
this
.
sourceType
=
sourceType
;
this
.
targetType
=
targetType
;
}
public
Class
<?>
getSourceType
()
{
return
sourceType
;
}
public
Class
<?>
getTargetType
()
{
return
targetType
;
}
@Override
public
boolean
equals
(
Object
obj
)
{
if
(
this
==
obj
)
{
return
true
;
}
if
(
obj
==
null
||
obj
.
getClass
()
!=
ConvertiblePair
.
class
)
{
return
false
;
}
ConvertiblePair
other
=
(
ConvertiblePair
)
obj
;
return
this
.
sourceType
.
equals
(
other
.
sourceType
)
&&
this
.
targetType
.
equals
(
other
.
targetType
);
}
@Override
public
int
hashCode
()
{
return
this
.
sourceType
.
hashCode
()
*
31
+
this
.
targetType
.
hashCode
();
}
}
}
src/main/java/cn/noexception/container/factory/convert/support/DefaultConversionService.java
0 → 100644
浏览文件 @
ec71c6cd
package
cn.noexception.container.factory.convert.support
;
import
cn.noexception.container.factory.convert.converter.ConverterRegistry
;
/**
* DefaultConversionService
*
* @author 吕滔
* @Date 2021/11/18 16:50
*/
public
class
DefaultConversionService
extends
GenericConversionService
{
public
DefaultConversionService
(){
addDefaultConverters
(
this
);
}
public
static
void
addDefaultConverters
(
ConverterRegistry
converterRegistry
)
{
// 添加各类类型转换工厂
converterRegistry
.
addConverterFactory
(
new
StringToNumberConverterFactory
());
}
}
src/main/java/cn/noexception/container/factory/convert/support/GenericConversionService.java
0 → 100644
浏览文件 @
ec71c6cd
package
cn.noexception.container.factory.convert.support
;
import
cn.noexception.container.factory.convert.ConversionService
;
import
cn.noexception.container.factory.convert.converter.Converter
;
import
cn.noexception.container.factory.convert.converter.ConverterFactory
;
import
cn.noexception.container.factory.convert.converter.ConverterRegistry
;
import
cn.noexception.container.factory.convert.converter.GenericConverter
;
import
java.lang.reflect.ParameterizedType
;
import
java.lang.reflect.Type
;
import
java.util.*
;
/**
* GenericConversionService
*
* @author 吕滔
* @Date 2021/11/19 10:35
*/
public
class
GenericConversionService
implements
ConversionService
,
ConverterRegistry
{
private
Map
<
GenericConverter
.
ConvertiblePair
,
GenericConverter
>
converters
=
new
HashMap
();
@Override
public
void
addConverter
(
Converter
<?,
?>
converter
)
{
GenericConverter
.
ConvertiblePair
typeInfo
=
getRequiredTypeInfo
(
converter
);
ConverterAdapter
converterAdapter
=
new
ConverterAdapter
(
typeInfo
,
converter
);
for
(
GenericConverter
.
ConvertiblePair
convertibleType
:
converterAdapter
.
getConvertibleTypes
())
{
converters
.
put
(
convertibleType
,
converterAdapter
);
}
}
private
final
class
ConverterAdapter
implements
GenericConverter
{
private
final
ConvertiblePair
typeInfo
;
private
final
Converter
<
Object
,
Object
>
converter
;
public
ConverterAdapter
(
ConvertiblePair
typeInfo
,
Converter
<?,
?>
converter
)
{
this
.
typeInfo
=
typeInfo
;
this
.
converter
=
(
Converter
<
Object
,
Object
>)
converter
;
}
@Override
public
Set
<
ConvertiblePair
>
getConvertibleTypes
()
{
return
Collections
.
singleton
(
typeInfo
);
}
@Override
public
Object
convert
(
Object
source
,
Class
sourceType
,
Class
targetType
)
{
return
converter
.
convert
(
source
);
}
}
private
GenericConverter
.
ConvertiblePair
getRequiredTypeInfo
(
Object
object
)
{
Type
[]
types
=
object
.
getClass
().
getGenericInterfaces
();
ParameterizedType
parameterizedType
=
(
ParameterizedType
)
types
[
0
];
Type
[]
actualTypeArguments
=
parameterizedType
.
getActualTypeArguments
();
Class
sourceType
=
(
Class
)
actualTypeArguments
[
0
];
Class
targetType
=
(
Class
)
actualTypeArguments
[
1
];
return
new
GenericConverter
.
ConvertiblePair
(
sourceType
,
targetType
);
}
@Override
public
void
addConverter
(
GenericConverter
converter
)
{
for
(
GenericConverter
.
ConvertiblePair
convertibleType
:
converter
.
getConvertibleTypes
())
{
converters
.
put
(
convertibleType
,
converter
);
}
}
@Override
public
void
addConverterFactory
(
ConverterFactory
<?,
?>
converterFactory
)
{
GenericConverter
.
ConvertiblePair
typeInfo
=
getRequiredTypeInfo
(
converterFactory
);
ConverterFactoryAdapter
converterFactoryAdapter
=
new
ConverterFactoryAdapter
(
typeInfo
,
converterFactory
);
for
(
GenericConverter
.
ConvertiblePair
convertibleType
:
converterFactoryAdapter
.
getConvertibleTypes
())
{
converters
.
put
(
convertibleType
,
converterFactoryAdapter
);
}
}
private
final
class
ConverterFactoryAdapter
implements
GenericConverter
{
private
final
ConvertiblePair
typeInfo
;
private
final
ConverterFactory
<
Object
,
Object
>
converterFactory
;
private
ConverterFactoryAdapter
(
ConvertiblePair
typeInfo
,
ConverterFactory
<?,
?>
converterFactory
)
{
this
.
typeInfo
=
typeInfo
;
this
.
converterFactory
=
(
ConverterFactory
<
Object
,
Object
>)
converterFactory
;
}
@Override
public
Set
<
ConvertiblePair
>
getConvertibleTypes
()
{
return
Collections
.
singleton
(
typeInfo
);
}
@Override
public
Object
convert
(
Object
source
,
Class
sourceType
,
Class
targetType
)
{
return
converterFactory
.
getConverter
(
targetType
).
convert
(
source
);
}
}
@Override
public
boolean
canConvert
(
Class
<?>
sourceType
,
Class
<?>
targetType
)
{
GenericConverter
converter
=
getConverter
(
sourceType
,
targetType
);
return
converter
!=
null
;
}
protected
GenericConverter
getConverter
(
Class
<?>
sourceType
,
Class
<?>
targetType
)
{
List
<
Class
<?>>
sourceCandidates
=
getClassHierarchy
(
sourceType
);
List
<
Class
<?>>
targetCandidates
=
getClassHierarchy
(
targetType
);
for
(
Class
<?>
sourceCandidate
:
sourceCandidates
)
{
for
(
Class
<?>
targetCandidate
:
targetCandidates
)
{
GenericConverter
.
ConvertiblePair
convertiblePair
=
new
GenericConverter
.
ConvertiblePair
(
sourceCandidate
,
targetCandidate
);
GenericConverter
converter
=
converters
.
get
(
convertiblePair
);
if
(
converter
!=
null
)
{
return
converter
;
}
}
}
return
null
;
}
private
List
<
Class
<?>>
getClassHierarchy
(
Class
<?>
clazz
)
{
List
<
Class
<?>>
hierarchy
=
new
ArrayList
<>();
while
(
clazz
!=
null
)
{
hierarchy
.
add
(
clazz
);
clazz
=
clazz
.
getSuperclass
();
}
return
hierarchy
;
}
@Override
public
<
T
>
T
convert
(
Object
source
,
Class
<
T
>
targetType
)
{
Class
<?>
sourceType
=
source
.
getClass
();
GenericConverter
converter
=
getConverter
(
sourceType
,
targetType
);
return
(
T
)
converter
.
convert
(
source
,
sourceType
,
targetType
);
}
}
src/main/java/cn/noexception/container/factory/convert/support/StringToNumberConverterFactory.java
0 → 100644
浏览文件 @
ec71c6cd
package
cn.noexception.container.factory.convert.support
;
import
cn.noexception.container.factory.convert.converter.Converter
;
import
cn.noexception.container.factory.convert.converter.ConverterFactory
;
import
cn.noexception.container.factory.utils.NumberUtils
;
import
jdk.internal.jline.internal.Nullable
;
/**
* StringToNumberConverterFactory
*
* @author 吕滔
* @Date 2021/11/19 15:39
*/
public
class
StringToNumberConverterFactory
implements
ConverterFactory
<
String
,
Number
>
{
@Override
public
<
T
extends
Number
>
Converter
<
String
,
T
>
getConverter
(
Class
<
T
>
targetType
)
{
return
new
StringToNumber
<>(
targetType
);
}
private
static
final
class
StringToNumber
<
T
extends
Number
>
implements
Converter
<
String
,
T
>{
private
final
Class
<
T
>
targetType
;
public
StringToNumber
(
Class
<
T
>
targetType
)
{
this
.
targetType
=
targetType
;
}
@Override
@Nullable
public
T
convert
(
String
source
)
{
if
(
source
.
isEmpty
())
{
return
null
;
}
return
NumberUtils
.
parseNumber
(
source
,
this
.
targetType
);
}
}
}
src/main/java/cn/noexception/container/factory/support/AbstractAutowiredCapableBeanFactory.java
浏览文件 @
ec71c6cd
...
...
@@ -2,11 +2,13 @@ package cn.noexception.container.factory.support;
import
cn.hutool.core.bean.BeanUtil
;
import
cn.hutool.core.util.StrUtil
;
import
cn.hutool.core.util.TypeUtil
;
import
cn.noexception.container.BeansException
;
import
cn.noexception.container.PropertyValue
;
import
cn.noexception.container.PropertyValues
;
import
cn.noexception.container.factory.*
;
import
cn.noexception.container.factory.config.*
;
import
cn.noexception.container.factory.convert.ConversionService
;
import
java.lang.reflect.Constructor
;
import
java.lang.reflect.Method
;
...
...
@@ -178,6 +180,16 @@ public abstract class AbstractAutowiredCapableBeanFactory extends AbstractBeanFa
// A 依赖 B,获取 B 的实例化
BeanReference
beanReference
=
(
BeanReference
)
value
;
value
=
getBean
(
beanReference
.
getBeanName
());
}
else
{
// 类型转换处理
Class
<?>
sourceType
=
value
.
getClass
();
Class
<?>
targetType
=
(
Class
<?>)
TypeUtil
.
getFieldType
(
bean
.
getClass
(),
name
);
ConversionService
conversionService
=
getConversionService
();
if
(
conversionService
!=
null
)
{
if
(
conversionService
.
canConvert
(
sourceType
,
targetType
))
{
value
=
conversionService
.
convert
(
value
,
targetType
);
}
}
}
// 属性填充
BeanUtil
.
setFieldValue
(
bean
,
name
,
value
);
...
...
src/main/java/cn/noexception/container/factory/support/AbstractBeanFactory.java
浏览文件 @
ec71c6cd
...
...
@@ -6,6 +6,7 @@ import cn.noexception.container.factory.FactoryBean;
import
cn.noexception.container.factory.config.BeanDefinition
;
import
cn.noexception.container.factory.config.BeanPostProcessor
;
import
cn.noexception.container.factory.config.ConfigurableBeanFactory
;
import
cn.noexception.container.factory.convert.ConversionService
;
import
cn.noexception.container.factory.utils.ClassUtils
;
import
cn.noexception.container.factory.utils.StringValueResolver
;
...
...
@@ -28,6 +29,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
*/
private
final
List
<
StringValueResolver
>
embeddedValueResolvers
=
new
ArrayList
<>();
private
ConversionService
conversionService
;
@Override
public
Object
getBean
(
String
name
)
throws
BeansException
{
return
doGetBean
(
name
,
null
);
...
...
@@ -97,4 +100,12 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
}
return
result
;
}
public
ConversionService
getConversionService
()
{
return
conversionService
;
}
public
void
setConversionService
(
ConversionService
conversionService
)
{
this
.
conversionService
=
conversionService
;
}
}
src/main/java/cn/noexception/container/factory/utils/NumberUtils.java
0 → 100644
浏览文件 @
ec71c6cd
package
cn.noexception.container.factory.utils
;
import
cn.hutool.core.lang.Assert
;
import
jdk.internal.jline.internal.Nullable
;
import
java.math.BigDecimal
;
import
java.math.BigInteger
;
import
java.text.DecimalFormat
;
import
java.text.NumberFormat
;
import
java.text.ParseException
;
import
java.util.Collections
;
import
java.util.HashSet
;
import
java.util.Set
;
/**
* NumberUtils
*
* @author 吕滔
* @Date 2021/11/19 15:44
*/
public
class
NumberUtils
{
private
static
final
BigInteger
LONG_MIN
=
BigInteger
.
valueOf
(
Long
.
MIN_VALUE
);
private
static
final
BigInteger
LONG_MAX
=
BigInteger
.
valueOf
(
Long
.
MAX_VALUE
);
/**
* Standard number types (all immutable):
* Byte, Short, Integer, Long, BigInteger, Float, Double, BigDecimal.
*/
public
static
final
Set
<
Class
<?>>
STANDARD_NUMBER_TYPES
;
static
{
Set
<
Class
<?>>
numberTypes
=
new
HashSet
<>(
8
);
numberTypes
.
add
(
Byte
.
class
);
numberTypes
.
add
(
Short
.
class
);
numberTypes
.
add
(
Integer
.
class
);
numberTypes
.
add
(
Long
.
class
);
numberTypes
.
add
(
BigInteger
.
class
);
numberTypes
.
add
(
Float
.
class
);
numberTypes
.
add
(
Double
.
class
);
numberTypes
.
add
(
BigDecimal
.
class
);
STANDARD_NUMBER_TYPES
=
Collections
.
unmodifiableSet
(
numberTypes
);
}
/**
* Convert the given number into an instance of the given target class.
* @param number the number to convert
* @param targetClass the target class to convert to
* @return the converted number
* @throws IllegalArgumentException if the target class is not supported
* (i.e. not a standard Number subclass as included in the JDK)
* @see java.lang.Byte
* @see java.lang.Short
* @see java.lang.Integer
* @see java.lang.Long
* @see java.math.BigInteger
* @see java.lang.Float
* @see java.lang.Double
* @see java.math.BigDecimal
*/
@SuppressWarnings
(
"unchecked"
)
public
static
<
T
extends
Number
>
T
convertNumberToTargetClass
(
Number
number
,
Class
<
T
>
targetClass
)
throws
IllegalArgumentException
{
Assert
.
notNull
(
number
,
"Number must not be null"
);
Assert
.
notNull
(
targetClass
,
"Target class must not be null"
);
if
(
targetClass
.
isInstance
(
number
))
{
return
(
T
)
number
;
}
else
if
(
Byte
.
class
==
targetClass
)
{
long
value
=
checkedLongValue
(
number
,
targetClass
);
if
(
value
<
Byte
.
MIN_VALUE
||
value
>
Byte
.
MAX_VALUE
)
{
raiseOverflowException
(
number
,
targetClass
);
}
return
(
T
)
Byte
.
valueOf
(
number
.
byteValue
());
}
else
if
(
Short
.
class
==
targetClass
)
{
long
value
=
checkedLongValue
(
number
,
targetClass
);
if
(
value
<
Short
.
MIN_VALUE
||
value
>
Short
.
MAX_VALUE
)
{
raiseOverflowException
(
number
,
targetClass
);
}
return
(
T
)
Short
.
valueOf
(
number
.
shortValue
());
}
else
if
(
Integer
.
class
==
targetClass
)
{
long
value
=
checkedLongValue
(
number
,
targetClass
);
if
(
value
<
Integer
.
MIN_VALUE
||
value
>
Integer
.
MAX_VALUE
)
{
raiseOverflowException
(
number
,
targetClass
);
}
return
(
T
)
Integer
.
valueOf
(
number
.
intValue
());
}
else
if
(
Long
.
class
==
targetClass
)
{
long
value
=
checkedLongValue
(
number
,
targetClass
);
return
(
T
)
Long
.
valueOf
(
value
);
}
else
if
(
BigInteger
.
class
==
targetClass
)
{
if
(
number
instanceof
BigDecimal
)
{
// do not lose precision - use BigDecimal's own conversion
return
(
T
)
((
BigDecimal
)
number
).
toBigInteger
();
}
else
{
// original value is not a Big* number - use standard long conversion
return
(
T
)
BigInteger
.
valueOf
(
number
.
longValue
());
}
}
else
if
(
Float
.
class
==
targetClass
)
{
return
(
T
)
Float
.
valueOf
(
number
.
floatValue
());
}
else
if
(
Double
.
class
==
targetClass
)
{
return
(
T
)
Double
.
valueOf
(
number
.
doubleValue
());
}
else
if
(
BigDecimal
.
class
==
targetClass
)
{
// always use BigDecimal(String) here to avoid unpredictability of BigDecimal(double)
// (see BigDecimal javadoc for details)
return
(
T
)
new
BigDecimal
(
number
.
toString
());
}
else
{
throw
new
IllegalArgumentException
(
"Could not convert number ["
+
number
+
"] of type ["
+
number
.
getClass
().
getName
()
+
"] to unsupported target class ["
+
targetClass
.
getName
()
+
"]"
);
}
}
/**
* Check for a {@code BigInteger}/{@code BigDecimal} long overflow
* before returning the given number as a long value.
* @param number the number to convert
* @param targetClass the target class to convert to
* @return the long value, if convertible without overflow
* @throws IllegalArgumentException if there is an overflow
* @see #raiseOverflowException
*/
private
static
long
checkedLongValue
(
Number
number
,
Class
<?
extends
Number
>
targetClass
)
{
BigInteger
bigInt
=
null
;
if
(
number
instanceof
BigInteger
)
{
bigInt
=
(
BigInteger
)
number
;
}
else
if
(
number
instanceof
BigDecimal
)
{
bigInt
=
((
BigDecimal
)
number
).
toBigInteger
();
}
// Effectively analogous to JDK 8's BigInteger.longValueExact()
if
(
bigInt
!=
null
&&
(
bigInt
.
compareTo
(
LONG_MIN
)
<
0
||
bigInt
.
compareTo
(
LONG_MAX
)
>
0
))
{
raiseOverflowException
(
number
,
targetClass
);
}
return
number
.
longValue
();
}
/**
* Raise an <em>overflow</em> exception for the given number and target class.
* @param number the number we tried to convert
* @param targetClass the target class we tried to convert to
* @throws IllegalArgumentException if there is an overflow
*/
private
static
void
raiseOverflowException
(
Number
number
,
Class
<?>
targetClass
)
{
throw
new
IllegalArgumentException
(
"Could not convert number ["
+
number
+
"] of type ["
+
number
.
getClass
().
getName
()
+
"] to target class ["
+
targetClass
.
getName
()
+
"]: overflow"
);
}
/**
* Parse the given {@code text} into a {@link Number} instance of the given
* target class, using the corresponding {@code decode} / {@code valueOf} method.
* <p>Trims all whitespace (leading, trailing, and in between characters) from
* the input {@code String} before attempting to parse the number.
* <p>Supports numbers in hex format (with leading "0x", "0X", or "#") as well.
* @param text the text to convert
* @param targetClass the target class to parse into
* @return the parsed number
* @throws IllegalArgumentException if the target class is not supported
* (i.e. not a standard Number subclass as included in the JDK)
* @see Byte#decode
* @see Short#decode
* @see Integer#decode
* @see Long#decode
* @see #decodeBigInteger(String)
* @see Float#valueOf
* @see Double#valueOf
* @see java.math.BigDecimal#BigDecimal(String)
*/
@SuppressWarnings
(
"unchecked"
)
public
static
<
T
extends
Number
>
T
parseNumber
(
String
text
,
Class
<
T
>
targetClass
)
{
Assert
.
notNull
(
text
,
"Text must not be null"
);
Assert
.
notNull
(
targetClass
,
"Target class must not be null"
);
String
trimmed
=
trimAllWhitespace
(
text
);
if
(
Byte
.
class
==
targetClass
)
{
return
(
T
)
(
isHexNumber
(
trimmed
)
?
Byte
.
decode
(
trimmed
)
:
Byte
.
valueOf
(
trimmed
));
}
else
if
(
Short
.
class
==
targetClass
)
{
return
(
T
)
(
isHexNumber
(
trimmed
)
?
Short
.
decode
(
trimmed
)
:
Short
.
valueOf
(
trimmed
));
}
else
if
(
Integer
.
class
==
targetClass
)
{
return
(
T
)
(
isHexNumber
(
trimmed
)
?
Integer
.
decode
(
trimmed
)
:
Integer
.
valueOf
(
trimmed
));
}
else
if
(
Long
.
class
==
targetClass
)
{
return
(
T
)
(
isHexNumber
(
trimmed
)
?
Long
.
decode
(
trimmed
)
:
Long
.
valueOf
(
trimmed
));
}
else
if
(
BigInteger
.
class
==
targetClass
)
{
return
(
T
)
(
isHexNumber
(
trimmed
)
?
decodeBigInteger
(
trimmed
)
:
new
BigInteger
(
trimmed
));
}
else
if
(
Float
.
class
==
targetClass
)
{
return
(
T
)
Float
.
valueOf
(
trimmed
);
}
else
if
(
Double
.
class
==
targetClass
)
{
return
(
T
)
Double
.
valueOf
(
trimmed
);
}
else
if
(
BigDecimal
.
class
==
targetClass
||
Number
.
class
==
targetClass
)
{
return
(
T
)
new
BigDecimal
(
trimmed
);
}
else
{
throw
new
IllegalArgumentException
(
"Cannot convert String ["
+
text
+
"] to target class ["
+
targetClass
.
getName
()
+
"]"
);
}
}
/**
* Parse the given {@code text} into a {@link Number} instance of the
* given target class, using the supplied {@link NumberFormat}.
* <p>Trims the input {@code String} before attempting to parse the number.
* @param text the text to convert
* @param targetClass the target class to parse into
* @param numberFormat the {@code NumberFormat} to use for parsing (if
* {@code null}, this method falls back to {@link #parseNumber(String, Class)})
* @return the parsed number
* @throws IllegalArgumentException if the target class is not supported
* (i.e. not a standard Number subclass as included in the JDK)
* @see java.text.NumberFormat#parse
* @see #convertNumberToTargetClass
* @see #parseNumber(String, Class)
*/
public
static
<
T
extends
Number
>
T
parseNumber
(
String
text
,
Class
<
T
>
targetClass
,
@Nullable
NumberFormat
numberFormat
)
{
if
(
numberFormat
!=
null
)
{
Assert
.
notNull
(
text
,
"Text must not be null"
);
Assert
.
notNull
(
targetClass
,
"Target class must not be null"
);
DecimalFormat
decimalFormat
=
null
;
boolean
resetBigDecimal
=
false
;
if
(
numberFormat
instanceof
DecimalFormat
)
{
decimalFormat
=
(
DecimalFormat
)
numberFormat
;
if
(
BigDecimal
.
class
==
targetClass
&&
!
decimalFormat
.
isParseBigDecimal
())
{
decimalFormat
.
setParseBigDecimal
(
true
);
resetBigDecimal
=
true
;
}
}
try
{
Number
number
=
numberFormat
.
parse
(
trimAllWhitespace
(
text
));
return
convertNumberToTargetClass
(
number
,
targetClass
);
}
catch
(
ParseException
ex
)
{
throw
new
IllegalArgumentException
(
"Could not parse number: "
+
ex
.
getMessage
());
}
finally
{
if
(
resetBigDecimal
)
{
decimalFormat
.
setParseBigDecimal
(
false
);
}
}
}
else
{
return
parseNumber
(
text
,
targetClass
);
}
}
public
static
String
trimAllWhitespace
(
String
str
)
{
if
(!
hasLength
(
str
))
{
return
str
;
}
int
len
=
str
.
length
();
StringBuilder
sb
=
new
StringBuilder
(
str
.
length
());
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
char
c
=
str
.
charAt
(
i
);
if
(!
Character
.
isWhitespace
(
c
))
{
sb
.
append
(
c
);
}
}
return
sb
.
toString
();
}
public
static
boolean
hasLength
(
@Nullable
String
str
)
{
return
(
str
!=
null
&&
!
str
.
isEmpty
());
}
/**
* Determine whether the given {@code value} String indicates a hex number,
* i.e. needs to be passed into {@code Integer.decode} instead of
* {@code Integer.valueOf}, etc.
*/
private
static
boolean
isHexNumber
(
String
value
)
{
int
index
=
(
value
.
startsWith
(
"-"
)
?
1
:
0
);
return
(
value
.
startsWith
(
"0x"
,
index
)
||
value
.
startsWith
(
"0X"
,
index
)
||
value
.
startsWith
(
"#"
,
index
));
}
/**
* Decode a {@link java.math.BigInteger} from the supplied {@link String} value.
* <p>Supports decimal, hex, and octal notation.
* @see BigInteger#BigInteger(String, int)
*/
private
static
BigInteger
decodeBigInteger
(
String
value
)
{
int
radix
=
10
;
int
index
=
0
;
boolean
negative
=
false
;
// Handle minus sign, if present.
if
(
value
.
startsWith
(
"-"
))
{
negative
=
true
;
index
++;
}
// Handle radix specifier, if present.
if
(
value
.
startsWith
(
"0x"
,
index
)
||
value
.
startsWith
(
"0X"
,
index
))
{
index
+=
2
;
radix
=
16
;
}
else
if
(
value
.
startsWith
(
"#"
,
index
))
{
index
++;
radix
=
16
;
}
else
if
(
value
.
startsWith
(
"0"
,
index
)
&&
value
.
length
()
>
1
+
index
)
{
index
++;
radix
=
8
;
}
BigInteger
result
=
new
BigInteger
(
value
.
substring
(
index
),
radix
);
return
(
negative
?
result
.
negate
()
:
result
);
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录