generified FactoryBeans and further Java 5 code style updates

This commit is contained in:
Juergen Hoeller
2009-02-25 00:34:22 +00:00
parent 555fa3b4c8
commit 160249c012
48 changed files with 346 additions and 335 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,8 +20,8 @@ import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.FactoryBean;
/**
* FactoryBean for Burlap proxies. Exposes the proxied service for
* use as a bean reference, using the specified service interface.
* {@link FactoryBean} for Burlap proxies. Exposes the proxied service
* for use as a bean reference, using the specified service interface.
*
* <p>Burlap is a slim, XML-based RPC protocol.
* For information on Burlap, see the
@@ -40,7 +40,7 @@ import org.springframework.beans.factory.FactoryBean;
* @see org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean
* @see org.springframework.remoting.rmi.RmiProxyFactoryBean
*/
public class BurlapProxyFactoryBean extends BurlapClientInterceptor implements FactoryBean {
public class BurlapProxyFactoryBean extends BurlapClientInterceptor implements FactoryBean<Object> {
private Object serviceProxy;
@@ -56,7 +56,7 @@ public class BurlapProxyFactoryBean extends BurlapClientInterceptor implements F
return this.serviceProxy;
}
public Class getObjectType() {
public Class<?> getObjectType() {
return getServiceInterface();
}

View File

@@ -20,8 +20,8 @@ import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.FactoryBean;
/**
* FactoryBean for Hessian proxies. Exposes the proxied service for
* use as a bean reference, using the specified service interface.
* {@link FactoryBean} for Hessian proxies. Exposes the proxied service
* for use as a bean reference, using the specified service interface.
*
* <p>Hessian is a slim, binary RPC protocol.
* For information on Hessian, see the
@@ -40,7 +40,7 @@ import org.springframework.beans.factory.FactoryBean;
* @see org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean
* @see org.springframework.remoting.rmi.RmiProxyFactoryBean
*/
public class HessianProxyFactoryBean extends HessianClientInterceptor implements FactoryBean {
public class HessianProxyFactoryBean extends HessianClientInterceptor implements FactoryBean<Object> {
private Object serviceProxy;
@@ -56,7 +56,7 @@ public class HessianProxyFactoryBean extends HessianClientInterceptor implements
return this.serviceProxy;
}
public Class getObjectType() {
public Class<?> getObjectType() {
return getServiceInterface();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,8 +20,8 @@ import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.FactoryBean;
/**
* FactoryBean for HTTP invoker proxies. Exposes the proxied service for
* use as a bean reference, using the specified service interface.
* {@link FactoryBean} for HTTP invoker proxies. Exposes the proxied service
* for use as a bean reference, using the specified service interface.
*
* <p>The service URL must be an HTTP URL exposing an HTTP invoker service.
* Optionally, a codebase URL can be specified for on-demand dynamic code download
@@ -48,7 +48,7 @@ import org.springframework.beans.factory.FactoryBean;
* @see org.springframework.remoting.caucho.BurlapProxyFactoryBean
*/
public class HttpInvokerProxyFactoryBean extends HttpInvokerClientInterceptor
implements FactoryBean {
implements FactoryBean<Object> {
private Object serviceProxy;
@@ -67,7 +67,7 @@ public class HttpInvokerProxyFactoryBean extends HttpInvokerClientInterceptor
return this.serviceProxy;
}
public Class getObjectType() {
public Class<?> getObjectType() {
return getServiceInterface();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,8 +22,8 @@ import org.springframework.beans.factory.FactoryBean;
import org.springframework.util.ClassUtils;
/**
* {@link org.springframework.beans.factory.FactoryBean} for a specific port of a
* JAX-RPC service. Exposes a proxy for the port, to be used for bean references.
* {@link FactoryBean} for a specific port of a JAX-RPC service.
* Exposes a proxy for the port, to be used for bean references.
* Inherits configuration properties from {@link JaxRpcPortClientInterceptor}.
*
* <p>This factory is typically used with an RMI service interface. Alternatively,
@@ -45,7 +45,7 @@ import org.springframework.util.ClassUtils;
* @see LocalJaxRpcServiceFactoryBean
*/
public class JaxRpcPortProxyFactoryBean extends JaxRpcPortClientInterceptor
implements FactoryBean, BeanClassLoaderAware {
implements FactoryBean<Object>, BeanClassLoaderAware {
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
@@ -77,7 +77,7 @@ public class JaxRpcPortProxyFactoryBean extends JaxRpcPortClientInterceptor
return this.serviceProxy;
}
public Class getObjectType() {
public Class<?> getObjectType() {
return getServiceInterface();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,7 +37,7 @@ import org.springframework.beans.factory.InitializingBean;
* @see JaxRpcPortProxyFactoryBean
*/
public class LocalJaxRpcServiceFactoryBean extends LocalJaxRpcServiceFactory
implements FactoryBean, InitializingBean {
implements FactoryBean<Service>, InitializingBean {
private Service service;
@@ -47,11 +47,11 @@ public class LocalJaxRpcServiceFactoryBean extends LocalJaxRpcServiceFactory
}
public Object getObject() throws Exception {
public Service getObject() throws Exception {
return this.service;
}
public Class getObjectType() {
public Class<? extends Service> getObjectType() {
return (this.service != null ? this.service.getClass() : Service.class);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -34,7 +34,7 @@ import org.springframework.util.ClassUtils;
* @see LocalJaxWsServiceFactoryBean
*/
public class JaxWsPortProxyFactoryBean extends JaxWsPortClientInterceptor
implements FactoryBean, BeanClassLoaderAware {
implements FactoryBean<Object>, BeanClassLoaderAware {
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
@@ -62,7 +62,7 @@ public class JaxWsPortProxyFactoryBean extends JaxWsPortClientInterceptor
return this.serviceProxy;
}
public Class getObjectType() {
public Class<?> getObjectType() {
return getServiceInterface();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2007 the original author or authors.
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -35,7 +35,8 @@ import org.springframework.beans.factory.InitializingBean;
* @see org.springframework.jndi.JndiObjectFactoryBean
* @see JaxWsPortProxyFactoryBean
*/
public class LocalJaxWsServiceFactoryBean extends LocalJaxWsServiceFactory implements FactoryBean, InitializingBean {
public class LocalJaxWsServiceFactoryBean extends LocalJaxWsServiceFactory
implements FactoryBean<Service>, InitializingBean {
private Service service;
@@ -44,11 +45,11 @@ public class LocalJaxWsServiceFactoryBean extends LocalJaxWsServiceFactory imple
this.service = createJaxWsService();
}
public Object getObject() throws Exception {
public Service getObject() {
return this.service;
}
public Class getObjectType() {
public Class<? extends Service> getObjectType() {
return (this.service != null ? this.service.getClass() : Service.class);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2005 the original author or authors.
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@ import org.springframework.beans.factory.FactoryBean;
import org.springframework.web.context.ServletContextAware;
/**
* FactoryBean that fetches a specific, existing ServletContext attribute.
* {@link FactoryBean} that fetches a specific, existing ServletContext attribute.
* Exposes that ServletContext attribute when used as bean reference,
* effectively making it available as named Spring bean instance.
*
@@ -36,7 +36,7 @@ import org.springframework.web.context.ServletContextAware;
* @since 1.1.4
* @see ServletContextParameterFactoryBean
*/
public class ServletContextAttributeFactoryBean implements FactoryBean, ServletContextAware {
public class ServletContextAttributeFactoryBean implements FactoryBean<Object>, ServletContextAware {
private String attributeName;
@@ -65,7 +65,7 @@ public class ServletContextAttributeFactoryBean implements FactoryBean, ServletC
return this.attribute;
}
public Class getObjectType() {
public Class<?> getObjectType() {
return (this.attribute != null ? this.attribute.getClass() : null);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2006 the original author or authors.
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@ import org.springframework.beans.factory.FactoryBean;
import org.springframework.web.context.ServletContextAware;
/**
* Simple FactoryBean that exposes the ServletContext for bean references.
* {@link FactoryBean} that exposes the ServletContext for bean references.
* Can be used as alternative to implementing the ServletContextAware
* callback interface. Allows for passing the ServletContext reference
* to a constructor argument or any custom bean property.
@@ -40,7 +40,7 @@ import org.springframework.web.context.ServletContextAware;
* @see org.springframework.web.context.ServletContextAware
* @see ServletContextAttributeFactoryBean
*/
public class ServletContextFactoryBean implements FactoryBean, ServletContextAware {
public class ServletContextFactoryBean implements FactoryBean<ServletContext>, ServletContextAware {
private ServletContext servletContext;
@@ -50,11 +50,11 @@ public class ServletContextFactoryBean implements FactoryBean, ServletContextAwa
}
public Object getObject() {
public ServletContext getObject() {
return this.servletContext;
}
public Class getObjectType() {
public Class<? extends ServletContext> getObjectType() {
return (this.servletContext != null ? this.servletContext.getClass() : ServletContext.class);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2005 the original author or authors.
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@ import org.springframework.beans.factory.FactoryBean;
import org.springframework.web.context.ServletContextAware;
/**
* FactoryBean that retrieves a specific ServletContext init parameter
* {@link FactoryBean} that retrieves a specific ServletContext init parameter
* (that is, a "context-param" defined in <code>web.xml</code>).
* Exposes that ServletContext init parameter when used as bean reference,
* effectively making it available as named Spring bean instance.
@@ -31,7 +31,7 @@ import org.springframework.web.context.ServletContextAware;
* @since 1.2.4
* @see ServletContextAttributeFactoryBean
*/
public class ServletContextParameterFactoryBean implements FactoryBean, ServletContextAware {
public class ServletContextParameterFactoryBean implements FactoryBean<String>, ServletContextAware {
private String initParamName;
@@ -56,11 +56,11 @@ public class ServletContextParameterFactoryBean implements FactoryBean, ServletC
}
public Object getObject() throws Exception {
public String getObject() {
return this.paramValue;
}
public Class getObjectType() {
public Class<String> getObjectType() {
return String.class;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2008 the original author or authors.
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,28 +28,29 @@ import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Servlet 2.3/2.4 {@link javax.servlet.Filter} that converts posted method parameters into HTTP methods, retrievable
* via {@link HttpServletRequest#getMethod()}. Since browsers currently only support GET and POST, a common technique -
* used by the Prototype library, for instance - is to use a normal POST with an additional hidden form field
* (<code>_method</code>) to pass the "real" HTTP method. This filter reads that parameter, and changes of {@link
* HttpServletRequestWrapper#getMethod()} accordingly.
* {@link javax.servlet.Filter} that converts posted method parameters into HTTP methods,
* retrievable via {@link HttpServletRequest#getMethod()}. Since browsers currently only
* support GET and POST, a common technique - used by the Prototype library, for instance -
* is to use a normal POST with an additional hidden form field (<code>_method</code>)
* to pass the "real" HTTP method. This filter reads that parameter, and changes of
* {@link HttpServletRequestWrapper#getMethod()} accordingly.
*
* <p/>The name of the request parameter defaults to <code>_method</code>, but can be changed via the {@link
* #setMethodParam(String) methodParam} property.
* <p>The name of the request parameter defaults to <code>_method</code>, but can be
* changed via the {@link #setMethodParam(String) methodParam} property.
*
* @author Arjen Poutsma
* @since 3.0
*/
public class HiddenHttpMethodFilter extends OncePerRequestFilter {
/** Default method parameter, i.e. <code>_method</code>. */
/** Default method parameter: <code>_method</code> */
public static final String DEFAULT_METHOD_PARAM = "_method";
private String methodParam = DEFAULT_METHOD_PARAM;
/**
* Set the parameter name to look for HTTP methods.
*
* @see #DEFAULT_METHOD_PARAM
*/
public void setMethodParam(String methodParam) {
@@ -59,8 +60,10 @@ public class HiddenHttpMethodFilter extends OncePerRequestFilter {
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if ("POST".equals(request.getMethod()) && StringUtils.hasLength(request.getParameter(methodParam))) {
String method = request.getParameter(methodParam).toUpperCase(Locale.ENGLISH);
String paramValue = request.getParameter(this.methodParam);
if ("POST".equals(request.getMethod()) && StringUtils.hasLength(paramValue)) {
String method = paramValue.toUpperCase(Locale.ENGLISH);
HttpServletRequest wrapper = new HttpMethodRequestWrapper(method, request);
filterChain.doFilter(wrapper, response);
}
@@ -69,21 +72,23 @@ public class HiddenHttpMethodFilter extends OncePerRequestFilter {
}
}
/**
* Simple {@link HttpServletRequest} wrapper that returns the supplied method for {@link
* HttpServletRequest#getMethod()}.
* Simple {@link HttpServletRequest} wrapper that returns the supplied method for
* {@link HttpServletRequest#getMethod()}.
*/
private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
private final String method;
private HttpMethodRequestWrapper(String method, HttpServletRequest request) {
public HttpMethodRequestWrapper(String method, HttpServletRequest request) {
super(request);
this.method = method;
}
public String getMethod() {
return method;
return this.method;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2008 the original author or authors.
* Copyright 2002-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -32,12 +32,12 @@ import org.springframework.util.FileCopyUtils;
import org.springframework.util.Md5HashUtils;
/**
* Servlet 2.3/2.4 {@link javax.servlet.Filter} that generates an <code>ETag</code> value based on the content on the
* response. This ETag is compared to the <code>If-None-Match</code> header of the request. If these headers are equal,
* the resonse content is not sent, but rather a 304 "Not Modified" status.
* <p/>
* <p/>Since the ETag is based on the response content, the response (or {@link org.springframework.web.servlet.View})
* is still rendered. As such, this filter only saves bandwith, not performance.
* {@link javax.servlet.Filter} that generates an <code>ETag</code> value based on the content
* on the response. This ETag is compared to the <code>If-None-Match</code> header of the request.
* If these headers are equal, the resonse content is not sent, but rather a 304 "Not Modified" status.
*
* <p>Since the ETag is based on the response content, the response (or {@link org.springframework.web.servlet.View})
* is still rendered. As such, this filter only saves bandwidth, not server performance.
*
* @author Arjen Poutsma
* @since 3.0
@@ -48,13 +48,15 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
private static String HEADER_IF_NONE_MATCH = "If-None-Match";
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
ShallowEtagResponseWrapper wrapper = new ShallowEtagResponseWrapper(response);
filterChain.doFilter(request, wrapper);
byte[] body = wrapper.toByteArray();
ShallowEtagResponseWrapper responseWrapper = new ShallowEtagResponseWrapper(response);
filterChain.doFilter(request, responseWrapper);
byte[] body = responseWrapper.toByteArray();
String responseETag = generateETagHeaderValue(body);
response.setHeader(HEADER_ETAG, responseETag);
@@ -76,11 +78,9 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
}
/**
* Generates the ETag header value from the given response body bytes array.
* <p/>
* <p/>Default implementation generates an MD5 hash.
*
* @param bytes the
* Generate the ETag header value from the given response body byte array.
* <p>The default implementation generates an MD5 hash.
* @param bytes the response bdoy as byte array
* @return the ETag header value
* @see Md5HashUtils
*/
@@ -91,10 +91,11 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
return builder.toString();
}
/**
* {@link HttpServletRequest} wrapper that buffers all content written to the {@linkplain #getOutputStream() output
* stream} and {@linkplain #getWriter() writer}, and allows this content to be retrieved via a {@link #toByteArray()
* byte array}.
* {@link HttpServletRequest} wrapper that buffers all content written to the
* {@linkplain #getOutputStream() output stream} and {@linkplain #getWriter() writer},
* and allows this content to be retrieved via a {@link #toByteArray() byte array}.
*/
private static class ShallowEtagResponseWrapper extends HttpServletResponseWrapper {
@@ -109,24 +110,25 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return outputStream;
public ServletOutputStream getOutputStream() {
return this.outputStream;
}
@Override
public PrintWriter getWriter() throws IOException {
if (writer == null) {
if (this.writer == null) {
String characterEncoding = getCharacterEncoding();
Writer targetWriter = (characterEncoding != null ?
new OutputStreamWriter(outputStream, characterEncoding) : new OutputStreamWriter(outputStream));
writer = new PrintWriter(targetWriter);
new OutputStreamWriter(this.outputStream, characterEncoding) :
new OutputStreamWriter(this.outputStream));
this.writer = new PrintWriter(targetWriter);
}
return writer;
return this.writer;
}
@Override
public void resetBuffer() {
content.reset();
this.content.reset();
}
@Override
@@ -136,16 +138,16 @@ public class ShallowEtagHeaderFilter extends OncePerRequestFilter {
}
private byte[] toByteArray() {
return content.toByteArray();
return this.content.toByteArray();
}
private class ResponseServletOutputStream extends ServletOutputStream {
@Override
public void write(int b) throws IOException {
content.write(b);
}
}
}

View File

@@ -29,15 +29,16 @@ import java.util.regex.Pattern;
import org.springframework.util.Assert;
/**
* Represents a URI template. An URI template is a URI-like string that contained variables marked of in braces
* (<code>{</code>, <code>}</code>), which can be expanded to produce a URI.
* <p/>
* See {@link #expand(Map)}, {@link #expand(String[])}, and {@link #match(String)} for example usages.
* Represents a URI template. An URI template is a URI-like String that contained variables
* marked of in braces (<code>{</code>, <code>}</code>), which can be expanded to produce a URI.
* <p>See {@link #expand(Map)}, {@link #expand(String[])}, and {@link #match(String)} for example usages.
*
* @author Arjen Poutsma
* @since 3.0
* @see <a href="http://bitworking.org/projects/URI-Templates/">URI Templates</a>
* @since 3.0
*/
public final class UriTemplate {
public class UriTemplate {
/**
* Captures URI template variable names.
@@ -49,15 +50,17 @@ public final class UriTemplate {
*/
private static final String VALUE_REGEX = "(.*)";
private final List<String> variableNames;
private final Pattern matchPattern;
private final String uriTemplate;
/**
* Constructs a new {@link UriTemplate} with the given string.
* @param uriTemplate the uri template string
* Construct a new {@link UriTemplate} with the given URI String.
* @param uriTemplate the URI template string
*/
public UriTemplate(String uriTemplate) {
Parser parser = new Parser(uriTemplate);
@@ -66,19 +69,20 @@ public final class UriTemplate {
this.matchPattern = parser.getMatchPattern();
}
/**
* Returns the names of the variables in the template, in order.
* Return the names of the variables in the template, in order.
* @return the template variable names
*/
public List<String> getVariableNames() {
return variableNames;
public final List<String> getVariableNames() {
return this.variableNames;
}
/**
* Given the map of variables, expands this template into a URI string. The map keys represent variable names, the
* map values variable values. The order of variables is not significant.
* <p/>
* Example:
* Given the Map of variables, expands this template into a URI.
* The Map keys represent variable names, the Map values variable values.
* The order of variables is not significant.
* <p>Example:
* <pre>
* UriTemplate template = new UriTemplate("http://example.com/hotels/{hotel}/bookings/{booking}");
* Map&lt;String, String&gt; uriVariables = new HashMap&lt;String, String&gt;();
@@ -87,57 +91,58 @@ public final class UriTemplate {
* System.out.println(template.expand(uriVariables));
* </pre>
* will print: <blockquote><code>http://example.com/hotels/1/bookings/42</code></blockquote>
* @param uriVariables the map of uri variables
* @return the expanded uri
* @throws IllegalArgumentException if <code>uriVariables</code> is <code>null</code>; or if it does not contain
* values for all the variable names
* @param uriVariables the map of URI variables
* @return the expanded URI
* @throws IllegalArgumentException if <code>uriVariables</code> is <code>null</code>;
* or if it does not contain values for all the variable names
*/
public URI expand(Map<String, String> uriVariables) {
Assert.notNull(uriVariables, "'uriVariables' must not be null");
String[] values = new String[variableNames.size()];
for (int i = 0; i < variableNames.size(); i++) {
String name = variableNames.get(i);
Assert.isTrue(uriVariables.containsKey(name), "'uriVariables' has no value for [" + name + "]");
String[] values = new String[this.variableNames.size()];
for (int i = 0; i < this.variableNames.size(); i++) {
String name = this.variableNames.get(i);
if (!uriVariables.containsKey(name)) {
throw new IllegalArgumentException("'uriVariables' Map has no value for '" + name + "'");
}
values[i] = uriVariables.get(name);
}
return expand(values);
}
/**
* Given an array of variables, expands this template into a URI string. The array represent variable values. The
* order of variables is significant.
* <p/>
* Example:
* <pre>
* Given an array of variables, expand this template into a full URI.
* The array represent variable values. The order of variables is significant.
* <p>Example:
* <pre class="code>
* UriTemplate template = new UriTemplate("http://example.com/hotels/{hotel}/bookings/{booking}");
* System.out.println(template.expand("1", "42));
* </pre>
* will print: <blockquote><code>http://example.com/hotels/1/bookings/42</code></blockquote>
* @param uriVariableValues the array of uri variables
* @return the expanded uri
* @throws IllegalArgumentException if <code>uriVariables</code> is <code>null</code>; or if it does not contain
* sufficient variables
* @param uriVariableValues the array of URI variables
* @return the expanded URI
* @throws IllegalArgumentException if <code>uriVariables</code> is <code>null</code>;
* or if it does not contain sufficient variables
*/
public URI expand(String... uriVariableValues) {
Assert.notNull(uriVariableValues, "'uriVariableValues' must not be null");
if (uriVariableValues.length != variableNames.size()) {
throw new IllegalArgumentException(
"Invalid amount of variables values in [" + uriTemplate + "]: expected " + variableNames.size() +
"; got " + uriVariableValues.length);
if (uriVariableValues.length != this.variableNames.size()) {
throw new IllegalArgumentException("Invalid amount of variables values in [" +
this.uriTemplate + "]: expected " + this.variableNames.size() +
"; got " + uriVariableValues.length);
}
Matcher m = NAMES_PATTERN.matcher(uriTemplate);
Matcher matcher = NAMES_PATTERN.matcher(this.uriTemplate);
StringBuffer buffer = new StringBuffer();
int i = 0;
while (m.find()) {
while (matcher.find()) {
String uriVariable = uriVariableValues[i++];
m.appendReplacement(buffer, uriVariable);
matcher.appendReplacement(buffer, uriVariable);
}
m.appendTail(buffer);
matcher.appendTail(buffer);
return encodeUri(buffer.toString());
}
/**
* Indicates whether the given URI matches this template.
* Indicate whether the given URI matches this template.
* @param uri the URI to match to
* @return <code>true</code> if it matches; <code>false</code> otherwise
*/
@@ -145,16 +150,15 @@ public final class UriTemplate {
if (uri == null) {
return false;
}
Matcher m = matchPattern.matcher(uri);
return m.matches();
Matcher matcher = this.matchPattern.matcher(uri);
return matcher.matches();
}
/**
* Matches the given URI to a map of variable values. Keys in the returned map are variable names, values are
* variable values, as occurred in the given URI.
* <p/>
* Example:
* <pre>
* Match the given URI to a map of variable values. Keys in the returned map are
* variable names, values are variable values, as occurred in the given URI.
* <p>Example:
* <pre class="code">
* UriTemplate template = new UriTemplate("http://example.com/hotels/{hotel}/bookings/{booking}");
* System.out.println(template.match("http://example.com/hotels/1/bookings/42"));
* </pre>
@@ -164,18 +168,24 @@ public final class UriTemplate {
*/
public Map<String, String> match(String uri) {
Assert.notNull(uri, "'uri' must not be null");
Map<String, String> result = new LinkedHashMap<String, String>(variableNames.size());
Matcher m = matchPattern.matcher(uri);
if (m.find()) {
for (int i = 1; i <= m.groupCount(); i++) {
String name = variableNames.get(i - 1);
String value = m.group(i);
Map<String, String> result = new LinkedHashMap<String, String>(this.variableNames.size());
Matcher matcher = this.matchPattern.matcher(uri);
if (matcher.find()) {
for (int i = 1; i <= matcher.groupCount(); i++) {
String name = this.variableNames.get(i - 1);
String value = matcher.group(i);
result.put(name, value);
}
}
return result;
}
@Override
public String toString() {
return this.uriTemplate;
}
private static URI encodeUri(String uri) {
try {
int idx = uri.indexOf(':');
@@ -190,41 +200,35 @@ public final class UriTemplate {
}
return result;
}
catch (URISyntaxException e) {
throw new IllegalArgumentException("Could not create URI from [" + uri + "]");
catch (URISyntaxException ex) {
throw new IllegalArgumentException("Could not create URI from [" + uri + "]: " + ex);
}
}
@Override
public String toString() {
return uriTemplate;
}
/**
* Static inner class to parse uri template strings into a matching regular expression.
*/
private static class Parser {
private List<String> variableNames = new LinkedList<String>();
private final List<String> variableNames = new LinkedList<String>();
private StringBuilder patternBuilder = new StringBuilder();
private final StringBuilder patternBuilder = new StringBuilder();
private Parser(String uriTemplate) {
Assert.hasText(uriTemplate, "'uriTemplate' must not be null");
Matcher m = NAMES_PATTERN.matcher(uriTemplate);
int end = 0;
while (m.find()) {
patternBuilder.append(encodeAndQuote(uriTemplate, end, m.start()));
patternBuilder.append(VALUE_REGEX);
variableNames.add(m.group(1));
this.patternBuilder.append(encodeAndQuote(uriTemplate, end, m.start()));
this.patternBuilder.append(VALUE_REGEX);
this.variableNames.add(m.group(1));
end = m.end();
}
patternBuilder.append(encodeAndQuote(uriTemplate, end, uriTemplate.length()));
int lastIdx = patternBuilder.length() - 1;
if (lastIdx >= 0 && patternBuilder.charAt(lastIdx) == '/') {
patternBuilder.deleteCharAt(lastIdx);
this.patternBuilder.append(encodeAndQuote(uriTemplate, end, uriTemplate.length()));
int lastIdx = this.patternBuilder.length() - 1;
if (lastIdx >= 0 && this.patternBuilder.charAt(lastIdx) == '/') {
this.patternBuilder.deleteCharAt(lastIdx);
}
}
@@ -238,13 +242,12 @@ public final class UriTemplate {
private List<String> getVariableNames() {
return Collections.unmodifiableList(variableNames);
return Collections.unmodifiableList(this.variableNames);
}
private Pattern getMatchPattern() {
return Pattern.compile(patternBuilder.toString());
return Pattern.compile(this.patternBuilder.toString());
}
}
}