Skip to content

Commit 3960a71

Browse files
committed
added 2 transformers to help representing ObjectId as strings
very useful for angularjs that removes all properties whose name start with $, due to issue 1463 angular/angular.js#1463 removed old angularjs workaround
1 parent 51f3c64 commit 3960a71

File tree

4 files changed

+171
-26
lines changed

4 files changed

+171
-26
lines changed

src/main/java/org/restheart/hal/metadata/RepresentationTransformer.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -149,12 +149,14 @@ private static RepresentationTransformer getSingleFromJson(DBObject props) throw
149149

150150
String name = (String) _name;
151151

152+
DBObject args;
153+
152154
if (_args == null || !(_args instanceof DBObject)) {
153-
throw new InvalidMetadataException((_args == null ? "missing '" : "invalid '") + RT_ARGS_ELEMENT_NAME + "' element. it must be an Object");
155+
args = null;
156+
} else {
157+
args = (DBObject) _args;
154158
}
155159

156-
DBObject args = (DBObject) _args;
157-
158160
return new RepresentationTransformer(phase, scope, name, args);
159161
}
160162
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* RESTHeart - the data REST API server
3+
* Copyright (C) SoftInstigate Srl
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Affero General Public License as
7+
* published by the Free Software Foundation, either version 3 of the
8+
* License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Affero General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Affero General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
package org.restheart.hal.metadata.singletons;
19+
20+
import com.mongodb.DBObject;
21+
import io.undertow.server.HttpServerExchange;
22+
import org.bson.types.ObjectId;
23+
import org.restheart.handlers.RequestContext;
24+
25+
/**
26+
*
27+
* @author Andrea Di Cesare <[email protected]>
28+
*
29+
* On RESPONSE phase this transformer replaces ObjectId with strings.
30+
*
31+
* <br>Example, document { "_id": {"$oid": "553f59d2e4b041ceaac64e33" }, a: 1 }
32+
* <br>GET -> { "_id": "553f59d2e4b041ceaac64e33", a:1 }
33+
*
34+
*/
35+
public class OidsAsStringsTransformer implements Transformer {
36+
/**
37+
*
38+
* @param exchange
39+
* @param context
40+
* @param contentToTransform
41+
* @param args
42+
*/
43+
@Override
44+
public void tranform(final HttpServerExchange exchange, final RequestContext context, DBObject contentToTransform, final DBObject args) {
45+
_transform(contentToTransform);
46+
}
47+
48+
private void _transform(DBObject data) {
49+
data.keySet().stream().forEach(key -> {
50+
Object value = data.get(key);
51+
52+
if (value instanceof DBObject) {
53+
_transform((DBObject)value);
54+
} else if (value instanceof ObjectId) {
55+
data.put(key, ((ObjectId)value).toString());
56+
}
57+
});
58+
}
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
* RESTHeart - the data REST API server
3+
* Copyright (C) SoftInstigate Srl
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU Affero General Public License as
7+
* published by the Free Software Foundation, either version 3 of the
8+
* License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Affero General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU Affero General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
package org.restheart.hal.metadata.singletons;
19+
20+
import com.mongodb.BasicDBList;
21+
import com.mongodb.DBObject;
22+
import io.undertow.server.HttpServerExchange;
23+
import java.util.HashSet;
24+
import java.util.Set;
25+
import java.util.regex.Pattern;
26+
import org.bson.types.ObjectId;
27+
import org.restheart.handlers.RequestContext;
28+
29+
/**
30+
*
31+
* @author Andrea Di Cesare <[email protected]>
32+
*
33+
* On REQUEST phase This transformer replaces strings that are valid ObjectIds
34+
* with ObjectIds.
35+
*
36+
* <br>Example:
37+
* <br>POST( { "_id": "553f59d2e4b041ceaac64e33", a:2 } -> { "_id": {"$oid":
38+
* "553f59d2e4b041ceaac64e33" }, a: 1 }
39+
*
40+
*/
41+
public class ValidOidsStringsAsOidsTransformer implements Transformer {
42+
/**
43+
*
44+
* @param exchange
45+
* @param context
46+
* @param contentToTransform
47+
* @param args names of properties to tranform eventually (if value is valid
48+
* ObjectId) as an array of strings (["_id", "prop2"]
49+
*/
50+
@Override
51+
public void tranform(final HttpServerExchange exchange, final RequestContext context, DBObject contentToTransform, final DBObject args) {
52+
// this set contains the names of the properties to transform eventually
53+
Set<String> propertiesToTransform = new HashSet<>();
54+
55+
if (args instanceof BasicDBList) {
56+
BasicDBList _ids = (BasicDBList) args;
57+
58+
_ids.forEach(propertyName -> {
59+
if (propertyName instanceof String) {
60+
propertiesToTransform.add((String) propertyName);
61+
62+
} else {
63+
context.addWarning("element in the args list is not a string: " + propertyName);
64+
}
65+
});
66+
67+
} else {
68+
context.addWarning("transformer wrong definition: args property must be an arrary of string (properties names).");
69+
}
70+
71+
_transform(contentToTransform, propertiesToTransform);
72+
}
73+
74+
private void _transform(DBObject data, Set<String> propertiesNames) {
75+
data.keySet().stream().forEach(key -> {
76+
Object value = data.get(key);
77+
78+
if (shouldTransform(key, propertiesNames)) {
79+
if (value instanceof String && ObjectId.isValid((String) value)) {
80+
data.put(key, new ObjectId((String) value));
81+
}
82+
}
83+
84+
if (value instanceof DBObject) {
85+
_transform((DBObject) value, propertiesNames);
86+
}
87+
});
88+
}
89+
90+
/**
91+
* @param key the name of the property to transform (in case of patch can
92+
* also use the dot notation)
93+
* @param propertiesToTransform the set of properties names to tranform if
94+
* their value is a valid ObjectId
95+
* @return true if the property should be transformed
96+
*/
97+
private boolean shouldTransform(String key, Set<String> propertiesToTransform) {
98+
if (key.contains(".")) {
99+
String keyTokens[] = key.split(Pattern.quote("."));
100+
101+
key = keyTokens[keyTokens.length - 1];
102+
}
103+
104+
return propertiesToTransform.contains(key);
105+
}
106+
}

src/main/java/org/restheart/handlers/injectors/BodyInjectorHandler.java

+1-23
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public void handleRequest(HttpServerExchange exchange, RequestContext context) t
103103
DBObject content;
104104

105105
if (isNotFormData(contentTypes)) { // json or hal+json
106-
final String contentString = workaroundAngularJSIssue1463(ChannelReader.read(exchange.getRequestChannel()));
106+
final String contentString = ChannelReader.read(exchange.getRequestChannel());
107107

108108
try {
109109
content = (DBObject) JSON.parse(contentString);
@@ -174,28 +174,6 @@ public void handleRequest(HttpServerExchange exchange, RequestContext context) t
174174
getNext().handleRequest(exchange, context);
175175
}
176176

177-
/**
178-
* need this to workaroung angularjs issue
179-
* https://github.com/angular/angular.js/issues/1463
180-
*
181-
* TODO: allow enabling the workaround via configuration option
182-
*
183-
* @param content
184-
* @return
185-
*/
186-
private static String workaroundAngularJSIssue1463(String contentString) {
187-
if (contentString == null)
188-
return null;
189-
190-
String ret = contentString.replaceAll("\"€oid\" *:", "\"\\$oid\" :");
191-
192-
if (!ret.equals(contentString)) {
193-
LOGGER.debug("Replaced €oid alias with $oid in message body. This is to workaround angularjs issue 1463 (https://github.com/angular/angular.js/issues/1463)");
194-
}
195-
196-
return ret;
197-
}
198-
199177
/**
200178
*
201179
* @param contentTypes

0 commit comments

Comments
 (0)