diff --git a/src/main/java/org/springframework/hateoas/core/CachingMappingDiscoverer.java b/src/main/java/org/springframework/hateoas/core/CachingMappingDiscoverer.java new file mode 100644 index 00000000..39d64ea0 --- /dev/null +++ b/src/main/java/org/springframework/hateoas/core/CachingMappingDiscoverer.java @@ -0,0 +1,73 @@ +package org.springframework.hateoas.core; + +import java.lang.reflect.Method; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class CachingMappingDiscoverer implements MappingDiscoverer { + private Map mappingCache = new ConcurrentHashMap(); + private MappingDiscoverer discoverer; + + public CachingMappingDiscoverer(MappingDiscoverer discoverer) { + this.discoverer = discoverer; + } + + @Override + public String getMapping(final Class type) { + String key = key(type, null); + return getMapping(key, new CachedCall() { + @Override + public String getMapping() { + return discoverer.getMapping(type); + } + }); + } + + @Override + public String getMapping(final Method method) { + String key = key(method.getDeclaringClass(), method); + return getMapping(key, new CachedCall() { + @Override + public String getMapping() { + return discoverer.getMapping(method); + } + }); + } + + @Override + public String getMapping(final Class type, final Method method) { + String key = key(type, method); + return getMapping(key, new CachedCall() { + @Override + public String getMapping() { + return discoverer.getMapping(type, method); + } + }); + } + + public String getMapping(String key, CachedCall cachedCall) { + if (mappingCache.containsKey(key)) { + return mappingCache.get(key); + } else { + String mapping = cachedCall.getMapping(); + mappingCache.put(key, mapping); + return mapping; + } + } + + private interface CachedCall { + String getMapping(); + } + + private String key(Class type, Method method) { + StringBuilder buf = new StringBuilder(); + buf.append(type.getName()); + if (method != null) { + buf.append(method.getName()); + for (Class par: method.getParameterTypes()) { + buf.append(par.getName()); + } + } + return buf.toString(); + } +} diff --git a/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilder.java b/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilder.java index 1aaca6fb..bc20f56a 100755 --- a/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilder.java +++ b/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilder.java @@ -62,6 +62,7 @@ public class ControllerLinkBuilder extends LinkBuilderSupport { - private static final MappingDiscoverer DISCOVERER = new AnnotationMappingDiscoverer(RequestMapping.class); + private static final MappingDiscoverer DISCOVERER = new CachingMappingDiscoverer( + new AnnotationMappingDiscoverer(RequestMapping.class)); private static final AnnotatedParametersParameterAccessor PATH_VARIABLE_ACCESSOR = new AnnotatedParametersParameterAccessor( new AnnotationAttribute(PathVariable.class)); private static final AnnotatedParametersParameterAccessor REQUEST_PARAM_ACCESSOR = new RequestParamParameterAccessor(); private List uriComponentsContributors = new ArrayList(); + private UriTemplateFactory uriTemplateFactory = new UriTemplateFactory(); /** * Configures the {@link UriComponentsContributor} to be used when building {@link Link} instances from method @@ -103,7 +106,7 @@ public class ControllerLinkBuilderFactory implements MethodLinkBuilderFactory values = new HashMap(); Iterator names = template.getVariableNames().iterator(); @@ -280,7 +283,7 @@ public class ControllerLinkBuilderFactory implements MethodLinkBuilderFactory templateCache = new ConcurrentHashMap(); + UriTemplate templateFor(String mapping) { + if (templateCache.containsKey(mapping)) { + return templateCache.get(mapping); + } else { + UriTemplate template = new UriTemplate(mapping); + templateCache.put(mapping, template); + return template; + } + } +}