Skip to content

Commit c7c0698

Browse files
authored
Merge pull request #3076 from harawata/extensible-mapwrapper
Allow custom map wrapper to handle keys with dots or brackets
2 parents 225d613 + f09520e commit c7c0698

File tree

6 files changed

+555
-45
lines changed

6 files changed

+555
-45
lines changed

src/main/java/org/apache/ibatis/reflection/MetaObject.java

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2009-2023 the original author or authors.
2+
* Copyright 2009-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -112,31 +112,11 @@ public boolean hasGetter(String name) {
112112

113113
public Object getValue(String name) {
114114
PropertyTokenizer prop = new PropertyTokenizer(name);
115-
if (!prop.hasNext()) {
116-
return objectWrapper.get(prop);
117-
}
118-
MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
119-
if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
120-
return null;
121-
}
122-
return metaValue.getValue(prop.getChildren());
115+
return objectWrapper.get(prop);
123116
}
124117

125118
public void setValue(String name, Object value) {
126-
PropertyTokenizer prop = new PropertyTokenizer(name);
127-
if (prop.hasNext()) {
128-
MetaObject metaValue = metaObjectForProperty(prop.getIndexedName());
129-
if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
130-
if (value == null) {
131-
// don't instantiate child path if value is null
132-
return;
133-
}
134-
metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory);
135-
}
136-
metaValue.setValue(prop.getChildren(), value);
137-
} else {
138-
objectWrapper.set(prop, value);
139-
}
119+
objectWrapper.set(new PropertyTokenizer(name), value);
140120
}
141121

142122
public MetaObject metaObjectForProperty(String name) {

src/main/java/org/apache/ibatis/reflection/wrapper/BaseWrapper.java

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2009-2023 the original author or authors.
2+
* Copyright 2009-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
2020

2121
import org.apache.ibatis.reflection.MetaObject;
2222
import org.apache.ibatis.reflection.ReflectionException;
23+
import org.apache.ibatis.reflection.SystemMetaObject;
2324
import org.apache.ibatis.reflection.property.PropertyTokenizer;
2425

2526
/**
@@ -42,6 +43,10 @@ protected Object resolveCollection(PropertyTokenizer prop, Object object) {
4243
}
4344

4445
protected Object getCollectionValue(PropertyTokenizer prop, Object collection) {
46+
if (collection == null) {
47+
throw new ReflectionException("Cannot get the value '" + prop.getIndexedName() + "' because the property '"
48+
+ prop.getName() + "' is null.");
49+
}
4550
if (collection instanceof Map) {
4651
return ((Map) collection).get(prop.getIndex());
4752
}
@@ -67,12 +72,16 @@ protected Object getCollectionValue(PropertyTokenizer prop, Object collection) {
6772
} else if (collection instanceof short[]) {
6873
return ((short[]) collection)[i];
6974
} else {
70-
throw new ReflectionException(
71-
"The '" + prop.getName() + "' property of " + collection + " is not a List or Array.");
75+
throw new ReflectionException("Cannot get the value '" + prop.getIndexedName() + "' because the property '"
76+
+ prop.getName() + "' is not Map, List or Array.");
7277
}
7378
}
7479

7580
protected void setCollectionValue(PropertyTokenizer prop, Object collection, Object value) {
81+
if (collection == null) {
82+
throw new ReflectionException("Cannot set the value '" + prop.getIndexedName() + "' because the property '"
83+
+ prop.getName() + "' is null.");
84+
}
7685
if (collection instanceof Map) {
7786
((Map) collection).put(prop.getIndex(), value);
7887
} else {
@@ -98,10 +107,29 @@ protected void setCollectionValue(PropertyTokenizer prop, Object collection, Obj
98107
} else if (collection instanceof short[]) {
99108
((short[]) collection)[i] = (Short) value;
100109
} else {
101-
throw new ReflectionException(
102-
"The '" + prop.getName() + "' property of " + collection + " is not a List or Array.");
110+
throw new ReflectionException("Cannot set the value '" + prop.getIndexedName() + "' because the property '"
111+
+ prop.getName() + "' is not Map, List or Array.");
103112
}
104113
}
105114
}
106115

116+
protected Object getChildValue(PropertyTokenizer prop) {
117+
MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
118+
if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
119+
return null;
120+
}
121+
return metaValue.getValue(prop.getChildren());
122+
}
123+
124+
protected void setChildValue(PropertyTokenizer prop, Object value) {
125+
MetaObject metaValue = metaObject.metaObjectForProperty(prop.getIndexedName());
126+
if (metaValue == SystemMetaObject.NULL_META_OBJECT) {
127+
if (value == null) {
128+
// don't instantiate child path if value is null
129+
return;
130+
}
131+
metaValue = instantiatePropertyValue(null, new PropertyTokenizer(prop.getName()), metaObject.getObjectFactory());
132+
}
133+
metaValue.setValue(prop.getChildren(), value);
134+
}
107135
}

src/main/java/org/apache/ibatis/reflection/wrapper/BeanWrapper.java

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2009-2023 the original author or authors.
2+
* Copyright 2009-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -42,18 +42,21 @@ public BeanWrapper(MetaObject metaObject, Object object) {
4242

4343
@Override
4444
public Object get(PropertyTokenizer prop) {
45-
if (prop.getIndex() != null) {
46-
Object collection = resolveCollection(prop, object);
47-
return getCollectionValue(prop, collection);
45+
if (prop.hasNext()) {
46+
return getChildValue(prop);
47+
} else if (prop.getIndex() != null) {
48+
return getCollectionValue(prop, resolveCollection(prop, object));
49+
} else {
50+
return getBeanProperty(prop, object);
4851
}
49-
return getBeanProperty(prop, object);
5052
}
5153

5254
@Override
5355
public void set(PropertyTokenizer prop, Object value) {
54-
if (prop.getIndex() != null) {
55-
Object collection = resolveCollection(prop, object);
56-
setCollectionValue(prop, collection, value);
56+
if (prop.hasNext()) {
57+
setChildValue(prop, value);
58+
} else if (prop.getIndex() != null) {
59+
setCollectionValue(prop, resolveCollection(prop, object), value);
5760
} else {
5861
setBeanProperty(prop, object, value);
5962
}

src/main/java/org/apache/ibatis/reflection/wrapper/MapWrapper.java

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2009-2023 the original author or authors.
2+
* Copyright 2009-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@
2929
*/
3030
public class MapWrapper extends BaseWrapper {
3131

32-
private final Map<String, Object> map;
32+
protected final Map<String, Object> map;
3333

3434
public MapWrapper(MetaObject metaObject, Map<String, Object> map) {
3535
super(metaObject);
@@ -38,18 +38,21 @@ public MapWrapper(MetaObject metaObject, Map<String, Object> map) {
3838

3939
@Override
4040
public Object get(PropertyTokenizer prop) {
41-
if (prop.getIndex() != null) {
42-
Object collection = resolveCollection(prop, map);
43-
return getCollectionValue(prop, collection);
41+
if (prop.hasNext()) {
42+
return getChildValue(prop);
43+
} else if (prop.getIndex() != null) {
44+
return getCollectionValue(prop, resolveCollection(prop, map));
45+
} else {
46+
return map.get(prop.getName());
4447
}
45-
return map.get(prop.getName());
4648
}
4749

4850
@Override
4951
public void set(PropertyTokenizer prop, Object value) {
50-
if (prop.getIndex() != null) {
51-
Object collection = resolveCollection(prop, map);
52-
setCollectionValue(prop, collection, value);
52+
if (prop.hasNext()) {
53+
setChildValue(prop, value);
54+
} else if (prop.getIndex() != null) {
55+
setCollectionValue(prop, resolveCollection(prop, map), value);
5356
} else {
5457
map.put(prop.getName(), value);
5558
}

0 commit comments

Comments
 (0)