Skip to content
This repository was archived by the owner on May 28, 2018. It is now read-only.

[declarative-linking] - Support query parameters and copy of request query params #263

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;

Expand Down Expand Up @@ -123,6 +126,33 @@ static URI buildURI(InjectLinkDescriptor link,
UriTemplateParser parser = new UriTemplateParser(template);
List<String> parameterNames = parser.getNames();
Map<String, Object> valueMap = getParameterValues(parameterNames, link, context, uriInfo);

// adds query parameters.
MultivaluedMap<String, String> query = link.getQueryParams();
for (Entry<String, List<String>> entry : query.entrySet()) {
//process each value from query parameter and get expression's result.
for (String val: entry.getValue()) {
ValueExpression valExpr =
expressionFactory.createValueExpression(context, val, String.class);
ub.queryParam(entry.getKey(), valExpr.getValue(context).toString());
}
}

/* If user needs injection of request query parameters */
if (link.copyFromRequestParams()) {
Set<String> excludes = link.excludeFromRequestParams();
for (Entry<String, List<String>> reqParam: uriInfo.getQueryParameters().entrySet()) {
if (excludes != null && !excludes.isEmpty()) {
/* Excludes the copy of this parameters */
if (excludes.contains(reqParam.getKey())) {
continue;
}
/* Rebuilds request params for link*/
ub.queryParam(reqParam.getKey(), reqParam.getValue().toArray());
}
}
}

return ub.buildFromMap(valueMap);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,37 @@ enum Style {
String value();
}

/**
* Specifies name-value pairs for Link's query part.
*/
LinkQueryParam[] queryParams() default {};

@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface LinkQueryParam {

/**
* Specifies the name of the link query parameter.
*/
String name();

/**
* Specifies the value of the link query parameter.
*/
String value();
}

/**
* Specifies that request query params must be include in Link.
*/
boolean copyRequestQueryParams() default false;

/**
* If request query params are copied to Link, then exclude query parameters from this list.
*/
String[] excludeFromRequestQueryParams() default {};


class Util {

public static Link buildLinkFromUri(URI uri, InjectLink link) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@

import org.glassfish.jersey.linking.mapping.ResourceMappingContext;

import javax.ws.rs.core.MultivaluedMap;

import java.util.Set;

/**
* Utility for working with @Ref annotations
*
Expand Down Expand Up @@ -75,4 +79,25 @@ interface InjectLinkDescriptor {
* @return the condition
*/
String getCondition();

/**
* Get the list of query parameters injected by @LinkQueryParam.
* @return the list of query parameters.
*/
MultivaluedMap<String, String> getQueryParams();

/**
* The request query parameters should be included in response Links.
* @return true if we need request query parameters.
*/
boolean copyFromRequestParams();

/**
* A list of request parameters keys to exclude from response links.
* It's used if copyFromRequestParams() is enabled.
*
* @return the list of parameters keys names to exclude.
*/
Set<String> excludeFromRequestParams();

}
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,24 @@
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ws.rs.BeanParam;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Link;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;

import org.glassfish.jersey.linking.InjectLink.LinkQueryParam;
import org.glassfish.jersey.linking.mapping.ResourceMappingContext;
import org.glassfish.jersey.server.model.AnnotatedMethod;
import org.glassfish.jersey.server.model.MethodList;
Expand All @@ -70,6 +77,9 @@ class InjectLinkFieldDescriptor extends FieldDescriptor implements InjectLinkDes
private InjectLink link;
private Class<?> type;
private Map<String, String> bindings;
private MultivaluedMap<String, String> queryParams;
private boolean copyFromRequestQueryParams = false;
private Set<String> excludeFromRequestQueryParams = null;

/**
* C'tor
Expand All @@ -86,6 +96,16 @@ class InjectLinkFieldDescriptor extends FieldDescriptor implements InjectLinkDes
for (Binding binding : l.bindings()) {
bindings.put(binding.name(), binding.value());
}
queryParams = new MultivaluedHashMap<>();
for (LinkQueryParam param: l.queryParams()) {
queryParams.add(param.name(), param.value());
}
copyFromRequestQueryParams = l.copyRequestQueryParams();
if (copyFromRequestQueryParams) {
excludeFromRequestQueryParams =
Collections.unmodifiableSet(
new HashSet<>(Arrays.asList(l.excludeFromRequestQueryParams())));
}
}

/**
Expand Down Expand Up @@ -262,4 +282,22 @@ public String getBinding(String name) {
public String getCondition() {
return link.condition();
}

@Override
public MultivaluedMap<String, String> getQueryParams() {
return queryParams;
}

@Override
public boolean copyFromRequestParams() {
return copyFromRequestQueryParams;
}

@Override
public Set<String> excludeFromRequestParams() {
if (!copyFromRequestQueryParams) {
return null;
}
return excludeFromRequestQueryParams;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,20 @@

package org.glassfish.jersey.linking;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.glassfish.jersey.linking.InjectLink.LinkQueryParam;
import org.glassfish.jersey.linking.InjectLink.Style;
import org.glassfish.jersey.linking.mapping.ResourceMappingContext;

import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;

/**
* Utility class for working with {@link org.glassfish.jersey.linking.InjectLink} annotations.
*
Expand All @@ -56,13 +64,27 @@ class LinkHeaderDescriptor implements InjectLinkDescriptor {

private InjectLink linkHeader;
private Map<String, String> bindings;
private MultivaluedMap<String, String> queryParams;
private boolean copyFromRequestQueryParams = false;
private Set<String> excludeFromRequestQueryParams = null;


LinkHeaderDescriptor(InjectLink linkHeader) {
this.linkHeader = linkHeader;
bindings = new HashMap<>();
for (Binding binding : linkHeader.bindings()) {
bindings.put(binding.name(), binding.value());
}
queryParams = new MultivaluedHashMap<>();
for (LinkQueryParam param : linkHeader.queryParams()) {
queryParams.add(param.name(), param.value());
}
copyFromRequestQueryParams = linkHeader.copyRequestQueryParams();
if (copyFromRequestQueryParams) {
excludeFromRequestQueryParams =
Collections.unmodifiableSet(
new HashSet<>(Arrays.asList(linkHeader.excludeFromRequestQueryParams())));
}
}

InjectLink getLinkHeader() {
Expand All @@ -85,4 +107,22 @@ public String getCondition() {
return linkHeader.condition();
}

@Override
public MultivaluedMap<String, String> getQueryParams() {
return queryParams;
}

@Override
public boolean copyFromRequestParams() {
return copyFromRequestQueryParams;
}

@Override
public Set<String> excludeFromRequestParams() {
if (!copyFromRequestQueryParams) {
return null;
}
return excludeFromRequestQueryParams;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@

import org.glassfish.jersey.internal.util.collection.MultivaluedStringMap;
import org.glassfish.jersey.linking.InjectLink.Extension;
import org.glassfish.jersey.linking.InjectLink.LinkQueryParam;
import org.glassfish.jersey.linking.mapping.ResourceMappingContext;
import org.glassfish.jersey.server.ExtendedUriInfo;
import org.glassfish.jersey.server.model.Resource;
Expand Down Expand Up @@ -123,11 +124,15 @@ public MultivaluedMap<String, String> getPathParameters(boolean decode) {
}

public MultivaluedMap<String, String> getQueryParameters() {
return new MultivaluedStringMap();
MultivaluedStringMap map = new MultivaluedStringMap();
map.add("q", "somevalue");
return map;
}

public MultivaluedMap<String, String> getQueryParameters(boolean decode) {
return new MultivaluedStringMap();
MultivaluedStringMap map = new MultivaluedStringMap();
map.add("q", "somevalue");
return map;
}

public List<String> getMatchedURIs() {
Expand Down Expand Up @@ -361,7 +366,6 @@ public String getId2() {

@Test
public void testConditional() {
System.out.println("EL");
HeaderProcessor<EntityF> instance = new HeaderProcessor(EntityF.class);
EntityF testClass = new EntityF();
List<String> headerValues = instance.getLinkHeaderValues(testClass, mockUriInfo, mockRmc);
Expand All @@ -370,4 +374,72 @@ public void testConditional() {
assertEquals("</application/resources/1>", headerValue);
}

@InjectLinks({
@InjectLink(
value = "${entity.id1}",
queryParams = { @LinkQueryParam (name = "page", value = "${instance.page}"),
@LinkQueryParam (name = "page", value = "${instance.page2}"),
}
)
})
public static class EntityQ {

public String getId1() {
return "1";
}

public String getPage() {
return "42";
}

public String getPage2() {
return "43";
}
}

@Test
public void testQueryParam() {
HeaderProcessor<EntityQ> instance = new HeaderProcessor(EntityQ.class);
EntityQ testClass = new EntityQ();
List<String> headerValues = instance.getLinkHeaderValues(testClass, mockUriInfo, mockRmc);
assertEquals(1, headerValues.size());
String headerValue = headerValues.get(0);
assertEquals("</application/resources/1?page=42&page=43>", headerValue);
}


@InjectLinks({
@InjectLink(
value = "${entity.id1}",
copyRequestQueryParams = true,
excludeFromRequestQueryParams = {"page"},
queryParams = {
@LinkQueryParam (name = "page", value = "${instance.page}"),
}
)
})
public static class EntityR {

public String getId1() {
return "1";
}

public String getPage() {
return "42";
}

public String getPage2() {
return "43";
}
}

@Test
public void testRequestQueryParam() {
HeaderProcessor<EntityR> instance = new HeaderProcessor(EntityR.class);
EntityR testClass = new EntityR();
List<String> headerValues = instance.getLinkHeaderValues(testClass, mockUriInfo, mockRmc);
assertEquals(1, headerValues.size());
String headerValue = headerValues.get(0);
assertEquals("</application/resources/1?page=42&q=somevalue>", headerValue);
}
}