Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
S
spring-boot
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DEMO
spring-boot
Commits
9e144093
Commit
9e144093
authored
Jul 26, 2013
by
Dave Syer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve test coverage in RelaxedDataBinder
parent
b1f4320c
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
200 additions
and
149 deletions
+200
-149
RelaxedDataBinder.java
...org/springframework/bootstrap/bind/RelaxedDataBinder.java
+154
-149
BindingPreparationTests.java
...ringframework/bootstrap/bind/BindingPreparationTests.java
+46
-0
No files found.
spring-bootstrap/src/main/java/org/springframework/bootstrap/bind/RelaxedDataBinder.java
View file @
9e144093
...
@@ -139,160 +139,35 @@ public class RelaxedDataBinder extends DataBinder {
...
@@ -139,160 +139,35 @@ public class RelaxedDataBinder extends DataBinder {
}
}
}
}
/**
* Normalize a bean property path to a format understood by a BeanWrapper. This is
* used so that
* <ul>
* <li>Fuzzy matching can be employed for bean property names</li>
* <li>Period separators can be used instead of indexing ([...]) for map keys</li>
* </ul>
*
* @param wrapper a bean wrapper for the object to bind
* @param path the bean path to bind
* @return a transformed path with correct bean wrapper syntax
*/
protected
String
normalizePath
(
BeanWrapper
wrapper
,
String
path
)
{
protected
String
normalizePath
(
BeanWrapper
wrapper
,
String
path
)
{
return
initializePath
(
wrapper
,
new
BeanPath
(
path
),
0
);
return
initializePath
(
wrapper
,
new
BeanPath
(
path
),
0
);
}
}
private
static
class
BeanPath
{
private
List
<
PathNode
>
nodes
;
public
BeanPath
(
String
path
)
{
this
.
nodes
=
splitPath
(
path
);
}
public
void
mapIndex
(
int
index
)
{
PathNode
node
=
this
.
nodes
.
get
(
index
);
if
(
node
instanceof
PropertyNode
)
{
node
=
((
PropertyNode
)
node
).
mapIndex
();
}
this
.
nodes
.
set
(
index
,
node
);
}
public
String
prefix
(
int
index
)
{
return
range
(
0
,
index
);
}
public
void
rename
(
int
index
,
String
name
)
{
this
.
nodes
.
get
(
index
).
name
=
name
;
}
public
String
name
(
int
index
)
{
if
(
index
<
this
.
nodes
.
size
())
{
return
this
.
nodes
.
get
(
index
).
name
;
}
return
null
;
}
public
int
length
()
{
return
this
.
nodes
.
size
();
}
private
String
range
(
int
start
,
int
end
)
{
StringBuilder
builder
=
new
StringBuilder
();
for
(
int
i
=
start
;
i
<
end
;
i
++)
{
PathNode
node
=
this
.
nodes
.
get
(
i
);
builder
.
append
(
node
);
}
if
(
builder
.
toString
().
startsWith
((
"."
)))
{
builder
.
replace
(
0
,
1
,
""
);
}
return
builder
.
toString
();
}
public
boolean
isArrayIndex
(
int
index
)
{
return
this
.
nodes
.
get
(
index
)
instanceof
ArrayIndexNode
;
}
public
boolean
isProperty
(
int
index
)
{
return
this
.
nodes
.
get
(
index
)
instanceof
PropertyNode
;
}
@Override
public
String
toString
()
{
return
prefix
(
this
.
nodes
.
size
());
}
private
static
class
PathNode
{
protected
String
name
;
public
PathNode
(
String
name
)
{
this
.
name
=
name
;
}
}
private
static
class
ArrayIndexNode
extends
PathNode
{
public
ArrayIndexNode
(
String
name
)
{
super
(
name
);
}
@Override
public
String
toString
()
{
return
"["
+
this
.
name
+
"]"
;
}
}
private
static
class
MapIndexNode
extends
PathNode
{
public
MapIndexNode
(
String
name
)
{
super
(
name
);
}
@Override
public
String
toString
()
{
return
"["
+
this
.
name
+
"]"
;
}
}
private
static
class
PropertyNode
extends
PathNode
{
public
PropertyNode
(
String
name
)
{
super
(
name
);
}
public
MapIndexNode
mapIndex
()
{
return
new
MapIndexNode
(
this
.
name
);
}
@Override
public
String
toString
()
{
return
"."
+
this
.
name
;
}
}
private
List
<
PathNode
>
splitPath
(
String
path
)
{
List
<
PathNode
>
nodes
=
new
ArrayList
<
PathNode
>();
for
(
String
name
:
StringUtils
.
delimitedListToStringArray
(
path
,
"."
))
{
for
(
String
sub
:
StringUtils
.
delimitedListToStringArray
(
name
,
"["
))
{
if
(
StringUtils
.
hasText
(
sub
))
{
if
(
sub
.
endsWith
(
"]"
))
{
sub
=
sub
.
substring
(
0
,
sub
.
length
()
-
1
);
if
(
sub
.
matches
(
"[0-9]+"
))
{
nodes
.
add
(
new
ArrayIndexNode
(
sub
));
}
else
{
nodes
.
add
(
new
MapIndexNode
(
sub
));
}
}
else
{
nodes
.
add
(
new
PropertyNode
(
sub
));
}
}
}
}
return
nodes
;
}
}
private
String
initializePath
(
BeanWrapper
wrapper
,
BeanPath
path
,
int
index
)
{
private
String
initializePath
(
BeanWrapper
wrapper
,
BeanPath
path
,
int
index
)
{
String
prefix
=
path
.
prefix
(
index
);
String
prefix
=
path
.
prefix
(
index
);
String
key
=
path
.
name
(
index
);
String
key
=
path
.
name
(
index
);
if
(
key
==
null
)
{
return
path
.
toString
();
}
if
(
path
.
isProperty
(
index
))
{
if
(
path
.
isProperty
(
index
))
{
key
=
getActualPropertyName
(
wrapper
,
prefix
,
key
);
key
=
getActualPropertyName
(
wrapper
,
prefix
,
key
);
path
.
rename
(
index
,
key
);
path
.
rename
(
index
,
key
);
}
}
if
(
index
>=
path
.
length
()
-
1
)
{
if
(
path
.
name
(++
index
)
==
null
)
{
return
path
.
toString
();
return
path
.
toString
();
}
}
String
name
=
path
.
prefix
(++
index
);
String
name
=
path
.
prefix
(
index
);
TypeDescriptor
descriptor
=
wrapper
.
getPropertyTypeDescriptor
(
name
);
TypeDescriptor
descriptor
=
wrapper
.
getPropertyTypeDescriptor
(
name
);
if
(
descriptor
==
null
||
descriptor
.
isMap
())
{
if
(
descriptor
==
null
||
descriptor
.
isMap
())
{
if
(
descriptor
!=
null
)
{
if
(
descriptor
!=
null
)
{
...
@@ -302,20 +177,18 @@ public class RelaxedDataBinder extends DataBinder {
...
@@ -302,20 +177,18 @@ public class RelaxedDataBinder extends DataBinder {
extendMapIfNecessary
(
wrapper
,
path
,
index
);
extendMapIfNecessary
(
wrapper
,
path
,
index
);
}
}
else
if
(
descriptor
.
isCollection
())
{
else
if
(
descriptor
.
isCollection
())
{
// TODO: test collection extension
extendCollectionIfNecessary
(
wrapper
,
path
,
index
);
extendCollectionIfNecessary
(
wrapper
,
path
,
index
);
}
}
else
if
(
descriptor
.
getType
().
equals
(
Object
.
class
))
{
else
if
(
descriptor
.
getType
().
equals
(
Object
.
class
))
{
path
.
mapIndex
(
index
);
path
.
mapIndex
(
index
);
name
=
path
.
prefix
(
index
+
1
);
String
next
=
path
.
prefix
(
index
+
1
);
if
(
wrapper
.
getPropertyValue
(
n
ame
)
==
null
)
{
if
(
wrapper
.
getPropertyValue
(
n
ext
)
==
null
)
{
wrapper
.
setPropertyValue
(
n
ame
,
new
LinkedHashMap
<
String
,
Object
>());
wrapper
.
setPropertyValue
(
n
ext
,
new
LinkedHashMap
<
String
,
Object
>());
}
}
}
}
if
(
index
<
path
.
length
())
{
return
initializePath
(
wrapper
,
path
,
index
);
return
initializePath
(
wrapper
,
path
,
index
);
}
return
path
.
toString
();
}
}
private
void
extendCollectionIfNecessary
(
BeanWrapper
wrapper
,
BeanPath
path
,
int
index
)
{
private
void
extendCollectionIfNecessary
(
BeanWrapper
wrapper
,
BeanPath
path
,
int
index
)
{
...
@@ -439,4 +312,136 @@ public class RelaxedDataBinder extends DataBinder {
...
@@ -439,4 +312,136 @@ public class RelaxedDataBinder extends DataBinder {
}
}
}
}
private
static
class
BeanPath
{
private
List
<
PathNode
>
nodes
;
public
BeanPath
(
String
path
)
{
this
.
nodes
=
splitPath
(
path
);
}
public
void
mapIndex
(
int
index
)
{
PathNode
node
=
this
.
nodes
.
get
(
index
);
if
(
node
instanceof
PropertyNode
)
{
node
=
((
PropertyNode
)
node
).
mapIndex
();
}
this
.
nodes
.
set
(
index
,
node
);
}
public
String
prefix
(
int
index
)
{
return
range
(
0
,
index
);
}
public
void
rename
(
int
index
,
String
name
)
{
this
.
nodes
.
get
(
index
).
name
=
name
;
}
public
String
name
(
int
index
)
{
if
(
index
<
this
.
nodes
.
size
())
{
return
this
.
nodes
.
get
(
index
).
name
;
}
return
null
;
}
private
String
range
(
int
start
,
int
end
)
{
StringBuilder
builder
=
new
StringBuilder
();
for
(
int
i
=
start
;
i
<
end
;
i
++)
{
PathNode
node
=
this
.
nodes
.
get
(
i
);
builder
.
append
(
node
);
}
if
(
builder
.
toString
().
startsWith
((
"."
)))
{
builder
.
replace
(
0
,
1
,
""
);
}
return
builder
.
toString
();
}
public
boolean
isArrayIndex
(
int
index
)
{
return
this
.
nodes
.
get
(
index
)
instanceof
ArrayIndexNode
;
}
public
boolean
isProperty
(
int
index
)
{
return
this
.
nodes
.
get
(
index
)
instanceof
PropertyNode
;
}
@Override
public
String
toString
()
{
return
prefix
(
this
.
nodes
.
size
());
}
private
static
class
PathNode
{
protected
String
name
;
public
PathNode
(
String
name
)
{
this
.
name
=
name
;
}
}
private
static
class
ArrayIndexNode
extends
PathNode
{
public
ArrayIndexNode
(
String
name
)
{
super
(
name
);
}
@Override
public
String
toString
()
{
return
"["
+
this
.
name
+
"]"
;
}
}
private
static
class
MapIndexNode
extends
PathNode
{
public
MapIndexNode
(
String
name
)
{
super
(
name
);
}
@Override
public
String
toString
()
{
return
"["
+
this
.
name
+
"]"
;
}
}
private
static
class
PropertyNode
extends
PathNode
{
public
PropertyNode
(
String
name
)
{
super
(
name
);
}
public
MapIndexNode
mapIndex
()
{
return
new
MapIndexNode
(
this
.
name
);
}
@Override
public
String
toString
()
{
return
"."
+
this
.
name
;
}
}
private
List
<
PathNode
>
splitPath
(
String
path
)
{
List
<
PathNode
>
nodes
=
new
ArrayList
<
PathNode
>();
for
(
String
name
:
StringUtils
.
delimitedListToStringArray
(
path
,
"."
))
{
for
(
String
sub
:
StringUtils
.
delimitedListToStringArray
(
name
,
"["
))
{
if
(
StringUtils
.
hasText
(
sub
))
{
if
(
sub
.
endsWith
(
"]"
))
{
sub
=
sub
.
substring
(
0
,
sub
.
length
()
-
1
);
if
(
sub
.
matches
(
"[0-9]+"
))
{
nodes
.
add
(
new
ArrayIndexNode
(
sub
));
}
else
{
nodes
.
add
(
new
MapIndexNode
(
sub
));
}
}
else
{
nodes
.
add
(
new
PropertyNode
(
sub
));
}
}
}
}
return
nodes
;
}
}
}
}
spring-bootstrap/src/test/java/org/springframework/bootstrap/bind/BindingPreparationTests.java
View file @
9e144093
...
@@ -132,6 +132,28 @@ public class BindingPreparationTests {
...
@@ -132,6 +132,28 @@ public class BindingPreparationTests {
assertNotNull
(
wrapper
.
getPropertyValue
(
"nested[foo]"
));
assertNotNull
(
wrapper
.
getPropertyValue
(
"nested[foo]"
));
}
}
@Test
public
void
testAutoGrowListOfMaps
()
throws
Exception
{
TargetWithNestedListOfMaps
target
=
new
TargetWithNestedListOfMaps
();
BeanWrapperImpl
wrapper
=
new
BeanWrapperImpl
(
target
);
wrapper
.
setAutoGrowNestedPaths
(
true
);
RelaxedDataBinder
binder
=
new
RelaxedDataBinder
(
target
);
binder
.
normalizePath
(
wrapper
,
"nested[0][foo]"
);
assertNotNull
(
wrapper
.
getPropertyValue
(
"nested"
));
assertNotNull
(
wrapper
.
getPropertyValue
(
"nested[0]"
));
}
@Test
public
void
testAutoGrowListOfLists
()
throws
Exception
{
TargetWithNestedListOfLists
target
=
new
TargetWithNestedListOfLists
();
BeanWrapperImpl
wrapper
=
new
BeanWrapperImpl
(
target
);
wrapper
.
setAutoGrowNestedPaths
(
true
);
RelaxedDataBinder
binder
=
new
RelaxedDataBinder
(
target
);
binder
.
normalizePath
(
wrapper
,
"nested[0][1]"
);
assertNotNull
(
wrapper
.
getPropertyValue
(
"nested"
));
assertNotNull
(
wrapper
.
getPropertyValue
(
"nested[0][1]"
));
}
@Test
@Test
public
void
testBeanWrapperCreatesNewNestedMaps
()
throws
Exception
{
public
void
testBeanWrapperCreatesNewNestedMaps
()
throws
Exception
{
TargetWithNestedMap
target
=
new
TargetWithNestedMap
();
TargetWithNestedMap
target
=
new
TargetWithNestedMap
();
...
@@ -213,6 +235,30 @@ public class BindingPreparationTests {
...
@@ -213,6 +235,30 @@ public class BindingPreparationTests {
}
}
}
}
public
static
class
TargetWithNestedListOfMaps
{
private
List
<
Map
<
String
,
String
>>
nested
;
public
List
<
Map
<
String
,
String
>>
getNested
()
{
return
this
.
nested
;
}
public
void
setNested
(
List
<
Map
<
String
,
String
>>
nested
)
{
this
.
nested
=
nested
;
}
}
public
static
class
TargetWithNestedListOfLists
{
private
List
<
List
<
String
>>
nested
;
public
List
<
List
<
String
>>
getNested
()
{
return
this
.
nested
;
}
public
void
setNested
(
List
<
List
<
String
>>
nested
)
{
this
.
nested
=
nested
;
}
}
public
static
class
TargetWithNestedMapOfBean
{
public
static
class
TargetWithNestedMapOfBean
{
private
Map
<
String
,
VanillaTarget
>
nested
;
private
Map
<
String
,
VanillaTarget
>
nested
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment