You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2009/03/12 19:53:28 UTC
svn commit: r752970 - in /cxf/trunk:
rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/
rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/
rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/
rt/frontend/jaxrs/src/main/java/org...
Author: sergeyb
Date: Thu Mar 12 18:53:27 2009
New Revision: 752970
URL: http://svn.apache.org/viewvc?rev=752970&view=rev
Log:
JAXRS : encoding related fixes
Modified:
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/XMLSource.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/MetadataMap.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriBuilderImpl.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/URITemplate.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/SourceProvider.java
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/HttpUtils.java
cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/client/WebClientTest.java
cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java
cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/HttpUtilsTest.java
cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSSoapBookTest.java
Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java?rev=752970&r1=752969&r2=752970&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/AbstractClient.java Thu Mar 12 18:53:27 2009
@@ -81,13 +81,15 @@
protected List<Interceptor> outInterceptors = new ModCountCopyOnWriteArrayList<Interceptor>();
protected ConduitSelector conduitSelector;
protected Bus bus;
-
+
private MultivaluedMap<String, String> requestHeaders = new MetadataMap<String, String>();
private ResponseBuilder responseBuilder;
private URI baseURI;
private UriBuilder currentBuilder;
+
+
protected AbstractClient(URI baseURI, URI currentURI) {
this.baseURI = baseURI;
this.currentBuilder = new UriBuilderImpl(currentURI);
@@ -235,7 +237,7 @@
* {@inheritDoc}
*/
public URI getCurrentURI() {
- return getCurrentBuilder().clone().build();
+ return getCurrentBuilder().clone().buildFromEncoded();
}
/**
Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java?rev=752970&r1=752969&r2=752970&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/ClientProxyImpl.java Thu Mar 12 18:53:27 2009
@@ -53,7 +53,6 @@
import org.apache.cxf.jaxrs.model.OperationResourceInfo;
import org.apache.cxf.jaxrs.provider.ProviderFactory;
import org.apache.cxf.jaxrs.utils.AnnotationUtils;
-import org.apache.cxf.jaxrs.utils.HttpUtils;
import org.apache.cxf.jaxrs.utils.InjectionUtils;
import org.apache.cxf.jaxrs.utils.ParameterType;
import org.apache.cxf.message.Message;
@@ -248,7 +247,7 @@
List<Parameter> indexList = getParameters(map, key);
List<Object> list = new ArrayList<Object>(indexList.size());
for (Parameter p : indexList) {
- list.add(encode(p, params[p.getIndex()].toString()));
+ list.add(params[p.getIndex()].toString());
}
return list;
}
@@ -265,7 +264,7 @@
List<Parameter> qs = getParameters(map, ParameterType.QUERY);
for (Parameter p : qs) {
if (params[p.getIndex()] != null) {
- ub.queryParam(p.getValue(), encode(p, params[p.getIndex()].toString()));
+ ub.queryParam(p.getValue(), params[p.getIndex()].toString());
}
}
}
@@ -275,7 +274,7 @@
List<Parameter> mx = getParameters(map, ParameterType.MATRIX);
for (Parameter p : mx) {
if (params[p.getIndex()] != null) {
- ub.matrixParam(p.getValue(), encode(p, params[p.getIndex()].toString()));
+ ub.matrixParam(p.getValue(), params[p.getIndex()].toString());
}
}
}
@@ -322,55 +321,43 @@
reportInvalidResourceMethod(ori.getMethodToInvoke(), "NO_CONTEXT_PARAMETERS");
}
- boolean isEncoded = AnnotationUtils.isEncoded(anns, ori);
PathParam a = AnnotationUtils.getAnnotation(anns, PathParam.class);
if (a != null) {
- return new Parameter(ParameterType.PATH, index, a.value(), isEncoded);
+ return new Parameter(ParameterType.PATH, index, a.value());
}
QueryParam q = AnnotationUtils.getAnnotation(anns, QueryParam.class);
if (q != null) {
- return new Parameter(ParameterType.QUERY, index, q.value(), isEncoded);
+ return new Parameter(ParameterType.QUERY, index, q.value());
}
MatrixParam m = AnnotationUtils.getAnnotation(anns, MatrixParam.class);
if (m != null) {
- return new Parameter(ParameterType.MATRIX, index, m.value(), isEncoded);
+ return new Parameter(ParameterType.MATRIX, index, m.value());
}
FormParam f = AnnotationUtils.getAnnotation(anns, FormParam.class);
if (f != null) {
- return new Parameter(ParameterType.FORM, index, f.value(), isEncoded);
+ return new Parameter(ParameterType.FORM, index, f.value());
}
HeaderParam h = AnnotationUtils.getAnnotation(anns, HeaderParam.class);
if (h != null) {
- return new Parameter(ParameterType.HEADER, index, h.value(), isEncoded);
+ return new Parameter(ParameterType.HEADER, index, h.value());
}
Parameter p = null;
CookieParam c = AnnotationUtils.getAnnotation(anns, CookieParam.class);
if (c != null) {
- p = new Parameter(ParameterType.COOKIE, index, c.value(), isEncoded);
+ p = new Parameter(ParameterType.COOKIE, index, c.value());
} else {
- p = new Parameter(ParameterType.REQUEST_BODY, index, null, isEncoded);
+ p = new Parameter(ParameterType.REQUEST_BODY, index, null);
}
return p;
}
- private static String encode(Parameter p, String value) {
- if (p.isEncoded()) {
- return value;
- }
- if (p.getType() == ParameterType.PATH || p.getType() == ParameterType.MATRIX) {
- return HttpUtils.pathEncode(value);
- } else {
- return HttpUtils.urlEncode(value);
- }
- }
-
private Object doChainedInvocation(URI uri, MultivaluedMap<String, String> headers,
OperationResourceInfo ori, Object[] params, int bodyIndex,
MultivaluedMap<ParameterType, Parameter> types) throws Throwable {
@@ -425,13 +412,11 @@
private ParameterType type;
private int ind;
private String aValue;
- private boolean isEncoded;
- public Parameter(ParameterType type, int ind, String aValue, boolean encoded) {
+ public Parameter(ParameterType type, int ind, String aValue) {
this.type = type;
this.ind = ind;
this.aValue = aValue;
- this.isEncoded = encoded;
}
public int getIndex() {
@@ -445,10 +430,6 @@
public ParameterType getType() {
return type;
}
-
- public boolean isEncoded() {
- return isEncoded;
- }
}
// TODO : what we really need to do is to refactor JAXRSOutInterceptor so that
Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java?rev=752970&r1=752969&r2=752970&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/WebClient.java Thu Mar 12 18:53:27 2009
@@ -259,6 +259,7 @@
* can be obtained too, see Client.getResponse()
*/
public <T> T invoke(String httpMethod, Object body, Class<T> responseClass) {
+
Response r = doInvoke(httpMethod, body, responseClass);
if (r.getStatus() >= 400) {
@@ -308,6 +309,7 @@
*/
public WebClient query(String name, Object ...values) {
getCurrentBuilder().queryParam(name, values);
+
return this;
}
@@ -473,6 +475,7 @@
try {
ResponseBuilder rb = setResponseBuilder(conn).clone();
Response currentResponse = rb.clone().build();
+
Object entity = readBody(currentResponse, conn, m, responseClass, responseClass,
new Annotation[]{});
rb.entity(entity);
@@ -484,7 +487,7 @@
}
protected HttpURLConnection getConnection(String methodName) {
- return createHttpConnection(getCurrentBuilder().clone().build(), methodName);
+ return createHttpConnection(getCurrentBuilder().clone().buildFromEncoded(), methodName);
}
private class BodyWriter extends AbstractOutDatabindingInterceptor {
Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/XMLSource.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/XMLSource.java?rev=752970&r1=752969&r2=752970&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/XMLSource.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/client/XMLSource.java Thu Mar 12 18:53:27 2009
@@ -46,11 +46,16 @@
public class XMLSource {
private InputSource source;
+ private RuntimeException exceptionToThrow;
public XMLSource(InputStream is) {
source = new InputSource(is);
}
+ public void setException(RuntimeException ex) {
+ exceptionToThrow = ex;
+ }
+
public <T> T getNode(String expression, Class<T> cls) {
return getNode(expression, CastUtils.cast(Collections.emptyMap(), String.class, String.class), cls);
}
@@ -61,6 +66,9 @@
try {
Node node = (Node)xpath.evaluate(expression, source, XPathConstants.NODE);
if (node == null) {
+ if (exceptionToThrow != null) {
+ throw exceptionToThrow;
+ }
return null;
}
DOMSource ds = new DOMSource(node);
Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/MetadataMap.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/MetadataMap.java?rev=752970&r1=752969&r2=752970&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/MetadataMap.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/MetadataMap.java Thu Mar 12 18:53:27 2009
@@ -33,11 +33,17 @@
private Map<K, List<V>> m;
public MetadataMap() {
- this(new LinkedHashMap<K, List<V>>());
+ this.m = new LinkedHashMap<K, List<V>>();
}
public MetadataMap(Map<K, List<V>> store) {
- this.m = store;
+
+ this.m = new LinkedHashMap<K, List<V>>();
+ if (store != null) {
+ for (Map.Entry<K, List<V>> entry : store.entrySet()) {
+ m.put(entry.getKey(), new ArrayList<V>(entry.getValue()));
+ }
+ }
}
public void add(K key, V value) {
Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriBuilderImpl.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriBuilderImpl.java?rev=752970&r1=752969&r2=752970&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriBuilderImpl.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/UriBuilderImpl.java Thu Mar 12 18:53:27 2009
@@ -30,8 +30,6 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
import javax.ws.rs.Path;
import javax.ws.rs.core.MultivaluedMap;
@@ -45,8 +43,6 @@
public class UriBuilderImpl extends UriBuilder {
- private static final Pattern DECODE_PATTERN = Pattern.compile("%[0-9a-fA-F][0-9a-fA-F]");
-
private String scheme;
private String userInfo;
private int port;
@@ -79,14 +75,45 @@
private URI doBuild(boolean fromEncoded, Object... values) {
try {
- String path = buildPath(fromEncoded);
- path = substituteVarargs(path, values);
- return new URI(scheme, userInfo, host, port, path, buildQuery(), fragment);
+ String thePath = buildPath(fromEncoded);
+ thePath = substituteVarargs(thePath, values);
+ return buildURI(fromEncoded, thePath);
} catch (URISyntaxException ex) {
throw new UriBuilderException("URI can not be built", ex);
}
}
+ private URI buildURI(boolean fromEncoded, String thePath) throws URISyntaxException {
+ String theQuery = buildQuery(fromEncoded);
+ // TODO : do encodePartiallyEncoded only once here, do not do it inside buildPath()
+ // buildFromEncoded and buildFromEncodedMap - we'll need to be careful such that
+ // path '/' seperators are not encoded so probably we'll need to create PathSegments
+ // again if fromEncoded is set
+ if (fromEncoded) {
+ StringBuilder b = new StringBuilder();
+ b.append(scheme).append("://");
+ if (userInfo != null) {
+ b.append(userInfo).append('@');
+ }
+ b.append(host);
+ if (port != -1) {
+ b.append(':').append(port);
+ }
+ if (thePath != null && thePath.length() > 0) {
+ b.append(thePath.startsWith("/") ? thePath : '/' + thePath);
+ }
+ if (theQuery != null && theQuery.length() != 0) {
+ b.append('?').append(theQuery);
+ }
+ if (fragment != null) {
+ b.append('#').append(fragment);
+ }
+ return new URI(b.toString());
+ } else {
+ return new URI(scheme, userInfo, host, port, thePath, theQuery, fragment);
+ }
+ }
+
private String substituteVarargs(String path, Object... values) {
Map<String, String> varValueMap = new HashMap<String, String>();
URITemplate templ = new URITemplate(path);
@@ -109,9 +136,13 @@
public URI buildFromEncoded(Object... values) throws IllegalArgumentException, UriBuilderException {
// Problem: multi-arg URI c-tor always forces encoding, operation contract would be broken;
// use os single-arg URI c-tor requires unnecessary concatenate-parse roundtrip.
- // Solution: decode back given values and pass as non-decoded to regular build() method
+ // While decoding back given values and passing as non-decoded to regular build() method
+ // is promising unfortunatley it causes the loss of encoded reserved values such as +,
+ // which might cause problems if consumers do rely on URLEncoder which would turn '+' into
+ // ' ' or would break the contract in when query parameters are expected to have %2B
+
for (int i = 0; i < values.length; i++) {
- values[i] = decodePartiallyEncoded(values[i].toString());
+ values[i] = HttpUtils.encodePartiallyEncoded(values[i].toString(), false);
}
return doBuild(true, values);
}
@@ -125,9 +156,9 @@
private URI doBuildFromMap(Map<String, ? extends Object> map, boolean fromEncoded)
throws IllegalArgumentException, UriBuilderException {
try {
- String path = buildPath(fromEncoded);
- path = substituteMapped(path, map);
- return new URI(scheme, userInfo, host, port, path, buildQuery(), fragment);
+ String thePath = buildPath(fromEncoded);
+ thePath = substituteMapped(thePath, map);
+ return buildURI(fromEncoded, thePath);
} catch (URISyntaxException ex) {
throw new UriBuilderException("URI can not be built", ex);
}
@@ -150,7 +181,8 @@
// see buildFromEncoded() comment
Map<String, String> decodedMap = new HashMap<String, String>(map.size());
for (Map.Entry<String, ? extends Object> entry : map.entrySet()) {
- decodedMap.put(entry.getKey(), decodePartiallyEncoded(entry.getValue().toString()));
+ decodedMap.put(entry.getKey(),
+ HttpUtils.encodePartiallyEncoded(entry.getValue().toString(), false));
}
return doBuildFromMap(decodedMap, true);
}
@@ -158,7 +190,16 @@
// CHECKSTYLE:OFF
@Override
public UriBuilder clone() {
- return new UriBuilderImpl(build());
+ UriBuilderImpl builder = new UriBuilderImpl();
+ builder.scheme = scheme;
+ builder.userInfo = userInfo;
+ builder.port = port;
+ builder.host = host;
+ builder.paths = new ArrayList<PathSegment>(paths);
+ builder.fragment = fragment;
+ builder.query = new MetadataMap<String, String>(query);
+ builder.matrix = new MetadataMap<String, String>(matrix);
+ return builder;
}
// CHECKSTYLE:ON
@@ -292,9 +333,9 @@
scheme = uri.getScheme();
port = uri.getPort();
host = uri.getHost();
- setPathAndMatrix(uri.getPath());
+ setPathAndMatrix(uri.getRawPath());
fragment = uri.getFragment();
- query = JAXRSUtils.getStructuredParams(uri.getQuery(), "&", true);
+ query = JAXRSUtils.getStructuredParams(uri.getRawQuery(), "&", false);
userInfo = uri.getUserInfo();
}
@@ -314,6 +355,7 @@
PathSegment ps = iter.next();
String p = ps.getPath();
if (p.length() != 0 || !iter.hasNext()) {
+ p = fromEncoded ? new URITemplate(p).encodeLiteralCharacters() : p;
if (!p.startsWith("/")) {
sb.append('/');
}
@@ -327,8 +369,8 @@
return sb.toString();
}
- private String buildQuery() {
- return buildParams(query, '&', false);
+ private String buildQuery(boolean fromEncoded) {
+ return buildParams(query, '&', fromEncoded);
}
@Override
@@ -417,24 +459,6 @@
}
/**
- * Decode partially encoded string. Decode only values that matches patter "percent char followed by two
- * hexadecimal digits".
- *
- * @param encoded fully or partially encoded string.
- * @return decoded string
- */
- private String decodePartiallyEncoded(String encoded) {
- Matcher m = DECODE_PATTERN.matcher(encoded);
- StringBuffer sb = new StringBuffer();
- while (m.find()) {
- String found = m.group();
- m.appendReplacement(sb, HttpUtils.pathDecode(found));
- }
- m.appendTail(sb);
- return sb.toString();
- }
-
- /**
* Query or matrix params convertion from object values vararg to list of strings. No encoding is
* provided.
*
@@ -464,13 +488,14 @@
*/
private String buildParams(MultivaluedMap<String, String> map, char separator,
boolean fromEncoded) {
+ boolean isQuery = separator == '&';
StringBuilder b = new StringBuilder();
for (Iterator<Map.Entry<String, List<String>>> it = map.entrySet().iterator(); it.hasNext();) {
Map.Entry<String, List<String>> entry = it.next();
for (Iterator<String> sit = entry.getValue().iterator(); sit.hasNext();) {
String val = sit.next();
if (fromEncoded) {
- val = decodePartiallyEncoded(val);
+ val = HttpUtils.encodePartiallyEncoded(val, isQuery);
}
b.append(entry.getKey()).append('=').append(val);
if (sit.hasNext() || it.hasNext()) {
Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/URITemplate.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/URITemplate.java?rev=752970&r1=752969&r2=752970&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/URITemplate.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/model/URITemplate.java Thu Mar 12 18:53:27 2009
@@ -257,6 +257,24 @@
return sb.toString();
}
+ /**
+ * Encoded literal characters surrounding template variables,
+ * ex. "a {id} b" will be encoded to "a%20{id}%20b"
+ * @return encoded value
+ */
+ public String encodeLiteralCharacters() {
+ StringBuilder sb = new StringBuilder();
+ Matcher matcher = TEMPLATE_NAMES_PATTERN.matcher(template);
+ int i = 0;
+ while (matcher.find()) {
+ sb.append(HttpUtils.encodePartiallyEncoded(template.substring(i, matcher.start()), false));
+ sb.append('{').append(matcher.group(1)).append('}');
+ i = matcher.end();
+ }
+ sb.append(HttpUtils.encodePartiallyEncoded(template.substring(i, template.length()), false));
+ return sb.toString();
+ }
+
public static URITemplate createTemplate(ClassResourceInfo cri, Path path) {
if (path == null) {
Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/SourceProvider.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/SourceProvider.java?rev=752970&r1=752969&r2=752970&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/SourceProvider.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/SourceProvider.java Thu Mar 12 18:53:27 2009
@@ -45,6 +45,8 @@
import org.w3c.dom.Document;
+import org.apache.cxf.jaxrs.client.XMLSource;
+
@Provider
@Produces({"application/xml", "text/xml" })
@Consumes({"application/xml", "text/xml" })
@@ -56,7 +58,7 @@
}
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mt) {
- return Source.class.isAssignableFrom(type);
+ return Source.class.isAssignableFrom(type) || XMLSource.class.isAssignableFrom(type);
}
public Object readFrom(Class<Object> source, Type genericType, Annotation[] annotations, MediaType m,
@@ -79,6 +81,8 @@
} else if (StreamSource.class.isAssignableFrom(source)
|| Source.class.isAssignableFrom(source)) {
return new StreamSource(is);
+ } else if (XMLSource.class.isAssignableFrom(source)) {
+ return new XMLSource(is);
}
throw new IOException("Unrecognized source");
Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/HttpUtils.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/HttpUtils.java?rev=752970&r1=752969&r2=752970&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/HttpUtils.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/HttpUtils.java Thu Mar 12 18:53:27 2009
@@ -29,6 +29,8 @@
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.PathSegment;
@@ -45,7 +47,7 @@
private static final String LOCAL_IP_ADDRESS = "127.0.0.1";
private static final String LOCAL_HOST = "localhost";
-
+ private static final Pattern ENCODE_PATTERN = Pattern.compile("%[0-9a-fA-F][0-9a-fA-F]");
private HttpUtils() {
}
@@ -73,12 +75,42 @@
String result = urlEncode(value);
// URLEncoder will encode '+' to %2B but will turn ' ' into '+'
+ // We need to retain '+' and encode ' ' as %20
if (result.indexOf('+') != -1) {
result = result.replace("+", "%20");
}
+ if (result.indexOf("%2B") != -1) {
+ result = result.replace("%2B", "+");
+ }
+
return result;
}
+ /**
+ * Encodes partially encoded string. Encode all values but those matching pattern
+ * "percent char followed by two hexadecimal digits".
+ *
+ * @param encoded fully or partially encoded string.
+ * @return fully encoded string
+ */
+ public static String encodePartiallyEncoded(String encoded, boolean query) {
+ if (encoded.length() == 0) {
+ return encoded;
+ }
+ Matcher m = ENCODE_PATTERN.matcher(encoded);
+ StringBuffer sb = new StringBuffer();
+ int i = 0;
+ while (m.find()) {
+ String before = encoded.substring(i, m.start());
+ sb.append(query ? HttpUtils.urlEncode(before) : HttpUtils.pathEncode(before));
+ sb.append(m.group());
+ i = m.end();
+ }
+ String tail = encoded.substring(i, encoded.length());
+ sb.append(query ? HttpUtils.urlEncode(tail) : HttpUtils.pathEncode(tail));
+ return sb.toString();
+ }
+
public static SimpleDateFormat getHttpDateFormat() {
SimpleDateFormat dateFormat =
new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
Modified: cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/client/WebClientTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/client/WebClientTest.java?rev=752970&r1=752969&r2=752970&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/client/WebClientTest.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/client/WebClientTest.java Thu Mar 12 18:53:27 2009
@@ -27,6 +27,14 @@
public class WebClientTest extends Assert {
+ @Test
+ public void testEncoding() {
+ URI u = WebClient.create("http://foo").path("bar+ %2B").matrix("a", "value+ ")
+ .query("b", "bv+ ").getCurrentURI();
+ System.out.println("'" + u.toString() + "'");
+ assertEquals("http://foo/bar+%20%2B;a=value+%20?b=bv%2B+", u.toString());
+ }
+
@Test
public void testBaseCurrentPath() {
assertEquals(URI.create("http://foo"), WebClient.create("http://foo").getBaseURI());
Modified: cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java?rev=752970&r1=752969&r2=752970&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/impl/UriBuilderImplTest.java Thu Mar 12 18:53:27 2009
@@ -68,6 +68,47 @@
}
@Test
+ public void testClone() throws Exception {
+ URI uri = new URI("http://bar");
+ URI newUri = new UriBuilderImpl(uri).clone().build();
+ assertEquals("URI is not built correctly", "http://bar", newUri.toString());
+ }
+
+ @Test
+ public void testClonePctEncodedFromUri() throws Exception {
+ URI uri = new URI("http://bar/foo%20");
+ URI newUri = new UriBuilderImpl(uri).clone().buildFromEncoded();
+ assertEquals("URI is not built correctly", "http://bar/foo%20", newUri.toString());
+ }
+
+ @Test
+ public void testClonePctEncoded() throws Exception {
+ URI uri = new URI("http://bar");
+ URI newUri = new UriBuilderImpl(uri)
+ .path("{a}").path("{b}")
+ .matrixParam("m", "m1 ", "m2+%20")
+ .queryParam("q", "q1 ", "q2+q3%20").clone().buildFromEncoded("a+ ", "b%2B%20 ");
+ assertEquals("URI is not built correctly",
+ "http://bar/a+%20/b%2B%20%20;m=m1%20;m=m2+%20?q=q1+&q=q2%2Bq3%20",
+ newUri.toString());
+ }
+
+ @Test
+ public void testEncodedPathQueryFromExistingURI() throws Exception {
+ URI uri = new URI("http://bar/foo+%20%2B?q=a+b%20%2B");
+ URI newUri = new UriBuilderImpl(uri).buildFromEncoded();
+ assertEquals("URI is not built correctly",
+ "http://bar/foo+%20%2B?q=a%2Bb%20%2B", newUri.toString());
+ }
+
+ @Test
+ public void testEncodedAddedQuery() throws Exception {
+ URI uri = new URI("http://bar");
+ URI newUri = new UriBuilderImpl(uri).queryParam("q", "a+b%20%2B").buildFromEncoded();
+ assertEquals("URI is not built correctly", "http://bar?q=a%2Bb%20%2B", newUri.toString());
+ }
+
+ @Test
public void testSchemeSpecificPart() throws Exception {
URI uri = new URI("http://bar");
URI newUri = new UriBuilderImpl(uri).scheme("https").schemeSpecificPart("foo/bar").build();
@@ -457,6 +498,7 @@
assertEquals("URI is not built correctly", new URI("http://foo/bar;p1=v1;p1=v2"), newUri);
}
+
@Test
public void testMatrixParamMultiSameNameNewVals() throws Exception {
URI uri = new URI("http://foo/bar;p1=v1");
Modified: cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/HttpUtilsTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/HttpUtilsTest.java?rev=752970&r1=752969&r2=752970&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/HttpUtilsTest.java (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/utils/HttpUtilsTest.java Thu Mar 12 18:53:27 2009
@@ -42,7 +42,12 @@
@Test
public void testPathEncode() {
- assertEquals("%2B%20", HttpUtils.pathEncode("+ "));
+ assertEquals("+%20", HttpUtils.pathEncode("+ "));
+ }
+
+ @Test
+ public void testURLEncode() {
+ assertEquals("%2B+", HttpUtils.urlEncode("+ "));
}
@Test
Modified: cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSSoapBookTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSSoapBookTest.java?rev=752970&r1=752969&r2=752970&view=diff
==============================================================================
--- cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSSoapBookTest.java (original)
+++ cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSSoapBookTest.java Thu Mar 12 18:53:27 2009
@@ -44,6 +44,7 @@
import org.apache.cxf.jaxrs.client.JAXRSClientFactory;
import org.apache.cxf.jaxrs.client.ResponseExceptionMapper;
import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.cxf.jaxrs.client.XMLSource;
import org.apache.cxf.jaxrs.ext.form.Form;
import org.apache.cxf.jaxrs.impl.MetadataMap;
import org.apache.cxf.testutil.common.AbstractBusClientServerTestBase;
@@ -100,11 +101,11 @@
}
@Test
- public void testGetBook123WebClientBean() throws Exception {
+ public void testGetBook123XMLSource() throws Exception {
String baseAddress = "http://localhost:9092/test/services/rest";
WebClient client = WebClient.create(baseAddress);
client.path("/bookstore/123").accept(MediaType.APPLICATION_XML_TYPE);
- Book b = client.get(Book.class);
+ Book b = client.get(XMLSource.class).getNode("/Book", Book.class);
assertEquals(123, b.getId());
assertEquals("CXF in Action", b.getName());
}