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

Commit 991998a

Browse files
author
Michal Gajdos
committed
JERSEY-2739: "NameBinding" results in a deployment failure
- Ignoring name binding when @PreMatching is present Change-Id: Ib441dbb02379ec25c7e2aadf5e59d3a07a01ee85 Signed-off-by: Michal Gajdos <[email protected]>
1 parent 921ad77 commit 991998a

File tree

3 files changed

+76
-30
lines changed

3 files changed

+76
-30
lines changed

core-server/src/main/java/org/glassfish/jersey/server/ApplicationHandler.java

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -780,7 +780,7 @@ public boolean apply(final ContractProvider input) {
780780
* parameter.
781781
*
782782
* @param all Collection of all filters to be processed.
783-
* @param preMatching Collection into which pre-matching filters should be added.
783+
* @param preMatchingFilters Collection into which pre-matching filters should be added.
784784
* @param componentBag Component bag
785785
* @param applicationNameBindings Collection of name binding annotations attached to the JAX-RS application.
786786
* @param inverseNameBoundMap Inverse name bound map into which the name bound providers should be inserted. The keys
@@ -789,7 +789,7 @@ public boolean apply(final ContractProvider input) {
789789
*/
790790
private static <T> MultivaluedMap<Class<? extends Annotation>, RankedProvider<T>> filterNameBound(
791791
final Iterable<RankedProvider<T>> all,
792-
final Collection<RankedProvider<ContainerRequestFilter>> preMatching,
792+
final Collection<RankedProvider<ContainerRequestFilter>> preMatchingFilters,
793793
final ComponentBag componentBag,
794794
final Collection<Class<? extends Annotation>> applicationNameBindings,
795795
final MultivaluedMap<RankedProvider<T>, Class<? extends Annotation>> inverseNameBoundMap) {
@@ -811,23 +811,30 @@ private static <T> MultivaluedMap<Class<? extends Annotation>, RankedProvider<T>
811811
model = ComponentBag.modelFor(providerClass);
812812
}
813813

814-
if (preMatching != null && providerClass.getAnnotation(PreMatching.class) != null) {
814+
final boolean preMatching = providerClass.getAnnotation(PreMatching.class) != null;
815+
if (preMatching && preMatchingFilters != null) {
815816
it.remove();
816-
preMatching.add(new RankedProvider<>((ContainerRequestFilter) provider.getProvider(),
817+
preMatchingFilters.add(new RankedProvider<>((ContainerRequestFilter) provider.getProvider(),
817818
model.getPriority(ContainerRequestFilter.class)));
818819
}
819820

820821
boolean nameBound = model.isNameBound();
821-
if (nameBound && !applicationNameBindings.isEmpty() && applicationNameBindings.containsAll(model.getNameBindings())) {
822+
if (nameBound
823+
&& !applicationNameBindings.isEmpty()
824+
&& applicationNameBindings.containsAll(model.getNameBindings())) {
822825
// override the name-bound flag
823826
nameBound = false;
824827
}
825828

826829
if (nameBound) { // not application-bound
827-
it.remove();
828-
for (final Class<? extends Annotation> binding : model.getNameBindings()) {
829-
result.add(binding, provider);
830-
inverseNameBoundMap.add(provider, binding);
830+
if (!preMatching) {
831+
it.remove();
832+
for (final Class<? extends Annotation> binding : model.getNameBindings()) {
833+
result.add(binding, provider);
834+
inverseNameBoundMap.add(provider, binding);
835+
}
836+
} else {
837+
LOGGER.warning(LocalizationMessages.PREMATCHING_ALSO_NAME_BOUND(providerClass));
831838
}
832839
}
833840
}

core-server/src/main/resources/org/glassfish/jersey/server/internal/localization.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ non.pub.sub.res.method=A sub-resource method, {0}, MUST be public scoped otherwi
164164
param.null="{0}" parameter is null.
165165
# {0} = parameter name; {1} = parameter type; {2} = field description
166166
parameter.unresolvable=Parameter {0} of type {1} from {2} is not resolvable to a concrete type.
167+
prematching.also.name.bound=@PreMatching provider, {0}, also annotated with a name binding annotation. Name binding will be ignored.
167168
# {0} = exception class name; {1} = exception message
168169
property.value.tostring.throws.exception=[{0} thrown from property value toString(): {1}]
169170
rc.not.modifiable=The resource configuration is not modifiable in this context.

tests/e2e/src/test/java/org/glassfish/jersey/tests/e2e/server/NameBindingTest.java

Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
33
*
4-
* Copyright (c) 2013-2014 Oracle and/or its affiliates. All rights reserved.
4+
* Copyright (c) 2013-2015 Oracle and/or its affiliates. All rights reserved.
55
*
66
* The contents of this file are subject to the terms of either the GNU
77
* General Public License Version 2 only ("GPL") or the Common Development
@@ -47,37 +47,47 @@
4747
import java.lang.annotation.Target;
4848
import java.util.Set;
4949

50+
import javax.ws.rs.DefaultValue;
5051
import javax.ws.rs.GET;
52+
import javax.ws.rs.HeaderParam;
5153
import javax.ws.rs.NameBinding;
5254
import javax.ws.rs.Path;
5355
import javax.ws.rs.container.ContainerRequestContext;
56+
import javax.ws.rs.container.ContainerRequestFilter;
5457
import javax.ws.rs.container.ContainerResponseContext;
5558
import javax.ws.rs.container.ContainerResponseFilter;
59+
import javax.ws.rs.container.PreMatching;
5660
import javax.ws.rs.core.Application;
5761
import javax.ws.rs.core.Response;
5862

5963
import org.glassfish.jersey.server.ResourceConfig;
6064
import org.glassfish.jersey.test.JerseyTest;
6165

6266
import org.junit.Test;
67+
import static org.hamcrest.core.Is.is;
6368
import static org.junit.Assert.assertEquals;
6469
import static org.junit.Assert.assertNull;
70+
import static org.junit.Assert.assertThat;
6571

6672
import jersey.repackaged.com.google.common.collect.Sets;
6773

6874
/**
69-
* @author Miroslav Fuksa (miroslav.fuksa at oracle.com)
75+
* Test-suite ensuring the correct functionality of name binding.
7076
*
77+
* @author Miroslav Fuksa
78+
* @author Michal Gajdos (michal.gajdos at oracle.com)
7179
*/
7280
public class NameBindingTest extends JerseyTest {
81+
7382
@Override
7483
protected Application configure() {
7584
return new ResourceConfig(Resource.class, FooResource.class, BarResource.class, FooBarResource.class, FooFilter.class,
76-
BarFilter.class, FooBarFilter.class);
85+
BarFilter.class, FooBarFilter.class, PreMatchingFooFilter.class);
7786
}
7887

7988
@Path("resource")
8089
public static class Resource {
90+
8191
@GET
8292
public String noBinding() {
8393
return "noBinding";
@@ -105,35 +115,53 @@ public String foobar() {
105115
return "foobar";
106116
}
107117

118+
@GET
119+
@Path("preMatchingNameBinding")
120+
public String preMatchingNameBinding(@HeaderParam("header") @DefaultValue("bar") final String header) {
121+
return header;
122+
}
108123
}
109124

110125
@NameBinding
111126
@Target({ElementType.TYPE, ElementType.METHOD})
112127
@Retention(value = RetentionPolicy.RUNTIME)
113128
public static @interface FooBinding {
129+
114130
}
115131

116132
@NameBinding
117133
@Target({ElementType.TYPE, ElementType.METHOD})
118134
@Retention(value = RetentionPolicy.RUNTIME)
119135
public static @interface BarBinding {
120-
}
121136

137+
}
122138

123139
@FooBinding
124140
public static class FooFilter implements ContainerResponseFilter {
125141

126142
@Override
127-
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
143+
public void filter(final ContainerRequestContext requestContext, final ContainerResponseContext responseContext) throws
144+
IOException {
128145
responseContext.getHeaders().add(this.getClass().getSimpleName(), "called");
129146
}
130147
}
131148

149+
@PreMatching
150+
@FooBinding
151+
public static class PreMatchingFooFilter implements ContainerRequestFilter {
152+
153+
@Override
154+
public void filter(final ContainerRequestContext requestContext) throws IOException {
155+
requestContext.getHeaders().putSingle("header", "foo");
156+
}
157+
}
158+
132159
@BarBinding
133160
public static class BarFilter implements ContainerResponseFilter {
134161

135162
@Override
136-
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
163+
public void filter(final ContainerRequestContext requestContext, final ContainerResponseContext responseContext) throws
164+
IOException {
137165
responseContext.getHeaders().add(this.getClass().getSimpleName(), "called");
138166
}
139167
}
@@ -143,12 +171,12 @@ public void filter(ContainerRequestContext requestContext, ContainerResponseCont
143171
public static class FooBarFilter implements ContainerResponseFilter {
144172

145173
@Override
146-
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
174+
public void filter(final ContainerRequestContext requestContext, final ContainerResponseContext responseContext) throws
175+
IOException {
147176
responseContext.getHeaders().add(this.getClass().getSimpleName(), "called");
148177
}
149178
}
150179

151-
152180
private static final Set<Class<?>> FILTERS = initialize();
153181

154182
private static Set<Class<?>> initialize() {
@@ -159,22 +187,20 @@ private static Set<Class<?>> initialize() {
159187
return set;
160188
}
161189

162-
163-
private void checkCalled(Response response, Class<?>... filtersThatShouldBeCalled) {
164-
Set<Class<?>> positiveFilters = Sets.newHashSet(filtersThatShouldBeCalled);
165-
for (Class<?> filter : FILTERS) {
190+
private void checkCalled(final Response response, final Class<?>... filtersThatShouldBeCalled) {
191+
final Set<Class<?>> positiveFilters = Sets.newHashSet(filtersThatShouldBeCalled);
192+
for (final Class<?> filter : FILTERS) {
166193
if (positiveFilters.contains(filter)) {
167-
assertEquals("Filter '" + filter.getSimpleName() + "' should be called.",
168-
"called", response.getHeaders().getFirst(filter.getSimpleName()));
194+
assertEquals("Filter '" + filter.getSimpleName() + "' should be called.", "called", response.getHeaders()
195+
.getFirst(filter.getSimpleName()));
169196
} else {
170-
assertNull("Filter '" + filter.getSimpleName() + "' should not be called.",
171-
response.getHeaders().get(filter.getSimpleName()));
197+
assertNull("Filter '" + filter.getSimpleName() + "' should not be called.", response.getHeaders().get(filter
198+
.getSimpleName()));
172199
}
173200
}
174201
}
175202

176-
177-
private Response _getResponse(String path) {
203+
private Response _getResponse(final String path) {
178204
final Response response = target().path(path).request().get();
179205
assertEquals(200, response.getStatus());
180206
return response;
@@ -190,6 +216,18 @@ public void testResourceFooBinding() {
190216
checkCalled(_getResponse("resource/foo"), FooFilter.class);
191217
}
192218

219+
/**
220+
* Reproducer for JERSEY-2739. Name bound annotation on a pre-matching filter should be ignored and the filter should be
221+
* invoked for each resource method (globally).
222+
*/
223+
@Test
224+
public void preMatchingNameBinding() {
225+
final Response response = _getResponse("resource/preMatchingNameBinding");
226+
227+
// Request filter - applied, even when the filter is name bound and the resource method is not.
228+
assertThat("Name binding on a @PreMatching filter not ignored.", response.readEntity(String.class), is("foo"));
229+
}
230+
193231
@Test
194232
public void testResourceBarBinding() {
195233
checkCalled(_getResponse("resource/bar"), BarFilter.class);
@@ -200,10 +238,10 @@ public void testResourceFooBarBinding() {
200238
checkCalled(_getResponse("resource/foobar"), FooFilter.class, BarFilter.class, FooBarFilter.class);
201239
}
202240

203-
204241
@Path("foo-resource")
205242
@FooBinding
206243
public static class FooResource extends Resource {
244+
207245
}
208246

209247
@Test
@@ -229,6 +267,7 @@ public void testFooResourceFooBarBinding() {
229267
@Path("bar-resource")
230268
@BarBinding
231269
public static class BarResource extends Resource {
270+
232271
}
233272

234273
@Test
@@ -251,11 +290,11 @@ public void testBarResourceFooBarBinding() {
251290
checkCalled(_getResponse("bar-resource/foobar"), BarFilter.class, FooFilter.class, FooBarFilter.class);
252291
}
253292

254-
255293
@Path("foobar-resource")
256294
@BarBinding
257295
@FooBinding
258296
public static class FooBarResource extends Resource {
297+
259298
}
260299

261300
@Test
@@ -278,5 +317,4 @@ public void testFooBarResourceFooBarBinding() {
278317
checkCalled(_getResponse("foobar-resource/foobar"), BarFilter.class, FooFilter.class, FooBarFilter.class);
279318
}
280319

281-
282320
}

0 commit comments

Comments
 (0)