#1324 - Fixed potential memory leak when creating many links.
We now avoid creating the UriTemplate instance for a Link if the Link does not contain curly braces in the first place. That allows us to remove the cache within UriTemplate in the first place. Related tickets: #1287.
This commit is contained in:
@@ -26,6 +26,7 @@ import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -88,7 +89,7 @@ public class Link implements Serializable {
|
||||
private String deprecation;
|
||||
private String profile;
|
||||
private String name;
|
||||
private @JsonIgnore UriTemplate template;
|
||||
private @JsonIgnore @Nullable UriTemplate template;
|
||||
private @JsonIgnore List<Affordance> affordances;
|
||||
|
||||
/**
|
||||
@@ -112,7 +113,7 @@ public class Link implements Serializable {
|
||||
*/
|
||||
@Deprecated
|
||||
public Link(String href, String rel) {
|
||||
this(UriTemplate.of(href), LinkRelation.of(rel));
|
||||
this(href, LinkRelation.of(rel));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,7 +125,7 @@ public class Link implements Serializable {
|
||||
*/
|
||||
@Deprecated
|
||||
public Link(String href, LinkRelation rel) {
|
||||
this(UriTemplate.of(href), rel);
|
||||
this(href, templateOrNull(href), rel, Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,8 +170,20 @@ public class Link implements Serializable {
|
||||
this.affordances = affordances;
|
||||
}
|
||||
|
||||
private Link(String href, @Nullable UriTemplate template, LinkRelation rel, List<Affordance> affordances) {
|
||||
|
||||
Assert.hasText(href, "Href must not be null or empty!");
|
||||
Assert.notNull(rel, "LinkRelation must not be null!");
|
||||
Assert.notNull(affordances, "Affordances must not be null!");
|
||||
|
||||
this.href = href;
|
||||
this.template = template;
|
||||
this.rel = rel;
|
||||
this.affordances = affordances;
|
||||
}
|
||||
|
||||
private Link(LinkRelation rel, String href, String hreflang, String media, String title, String type,
|
||||
String deprecation, String profile, String name, UriTemplate template, List<Affordance> affordances) {
|
||||
String deprecation, String profile, String name, @Nullable UriTemplate template, List<Affordance> affordances) {
|
||||
|
||||
this.rel = rel;
|
||||
this.href = href;
|
||||
@@ -320,7 +333,7 @@ public class Link implements Serializable {
|
||||
*/
|
||||
@JsonIgnore
|
||||
public List<String> getVariableNames() {
|
||||
return template.getVariableNames();
|
||||
return template == null ? Collections.emptyList() : template.getVariableNames();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -330,7 +343,7 @@ public class Link implements Serializable {
|
||||
*/
|
||||
@JsonIgnore
|
||||
public List<TemplateVariable> getVariables() {
|
||||
return template.getVariables();
|
||||
return template == null ? Collections.emptyList() : template.getVariables();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -339,7 +352,7 @@ public class Link implements Serializable {
|
||||
* @return
|
||||
*/
|
||||
public boolean isTemplated() {
|
||||
return !template.getVariables().isEmpty();
|
||||
return template == null ? false : !template.getVariables().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -349,7 +362,7 @@ public class Link implements Serializable {
|
||||
* @return
|
||||
*/
|
||||
public Link expand(Object... arguments) {
|
||||
return of(template.expand(arguments).toString(), getRel());
|
||||
return template == null ? this : of(template.expand(arguments).toString(), getRel());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -359,7 +372,7 @@ public class Link implements Serializable {
|
||||
* @return
|
||||
*/
|
||||
public Link expand(Map<String, ?> arguments) {
|
||||
return of(template.expand(arguments).toString(), getRel());
|
||||
return template == null ? this : of(template.expand(arguments).toString(), getRel());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -663,16 +676,22 @@ public class Link implements Serializable {
|
||||
|
||||
@JsonProperty
|
||||
public UriTemplate getTemplate() {
|
||||
return this.template;
|
||||
return template == null ? UriTemplate.of(href) : this.template;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
|
||||
if (this == o)
|
||||
if (this == o) {
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
Link link = (Link) o;
|
||||
return Objects.equals(this.rel, link.rel) && Objects.equals(this.href, link.href)
|
||||
&& Objects.equals(this.hreflang, link.hreflang) && Objects.equals(this.media, link.media)
|
||||
@@ -681,6 +700,10 @@ public class Link implements Serializable {
|
||||
&& Objects.equals(this.name, link.name) && Objects.equals(this.affordances, link.affordances);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
||||
@@ -727,4 +750,12 @@ public class Link implements Serializable {
|
||||
|
||||
return linkString;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static UriTemplate templateOrNull(String href) {
|
||||
|
||||
Assert.notNull(href, "Href must not be null!");
|
||||
|
||||
return href.contains("{") ? UriTemplate.of(href) : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ import java.util.stream.Collectors;
|
||||
import org.springframework.hateoas.TemplateVariable.VariableType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ConcurrentReferenceHashMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.util.DefaultUriBuilderFactory;
|
||||
import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode;
|
||||
@@ -55,8 +54,6 @@ public class UriTemplate implements Iterable<TemplateVariable>, Serializable {
|
||||
private static final Pattern VARIABLE_REGEX = Pattern.compile("\\{([\\?\\&#/]?)([\\w\\,*]+)\\}");
|
||||
private static final long serialVersionUID = -1007874653930162262L;
|
||||
|
||||
private static final Map<String, UriTemplate> CACHE = new ConcurrentReferenceHashMap<>();
|
||||
|
||||
private final TemplateVariables variables;
|
||||
private String baseUri;
|
||||
private transient UriBuilderFactory factory;
|
||||
@@ -134,7 +131,7 @@ public class UriTemplate implements Iterable<TemplateVariable>, Serializable {
|
||||
|
||||
Assert.hasText(template, "Template must not be null or empty!");
|
||||
|
||||
return CACHE.computeIfAbsent(template, UriTemplate::new);
|
||||
return new UriTemplate(template);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,7 +144,7 @@ public class UriTemplate implements Iterable<TemplateVariable>, Serializable {
|
||||
|
||||
Assert.hasText(template, "Template must not be null or empty!");
|
||||
|
||||
return CACHE.computeIfAbsent(template, UriTemplate::new).with(variables);
|
||||
return new UriTemplate(template).with(variables);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user