Discussion:
JAX-RS Client Proxies Don't Handle @HeaderParam Set<String> Properly
James Carman
2018-10-03 21:33:07 UTC
Permalink
Suppose I have a service like this:

@Path("/")
public interface HeaderSetResource {
@GET
@Path("/hello")
@Produces(TEXT_PLAIN)
String sayHello(@HeaderParam("names") Set<String> names);
}


This test case fails:

@RunWith(MockitoJUnitRunner.class)
public class HeaderSetTest {

@Mock
private HeaderSetResource resourceMock;

private Server server;
private String address;


private void callHello(Set<String> names) {
final Invocation.Builder builder = webTarget().path("hello").request();
names.forEach(name -> builder.header("names", name));
builder.get();
}

public HeaderSetResource clientProxy() {
final JAXRSClientFactoryBean factoryBean = new JAXRSClientFactoryBean();
factoryBean.setFeatures(Collections.singletonList(new
LoggingFeature()));
factoryBean.setResourceClass(HeaderSetResource.class);
factoryBean.setAddress(address);
return factoryBean.create(HeaderSetResource.class);
}

@Before
public void createServer() {
String port = "10090";
address = String.format("http://localhost:%s/", port);

final JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
sf.setBus(BusFactory.getDefaultBus(true));
sf.setResourceClasses(HeaderSetResource.class);
sf.setFeatures(Collections.singletonList(new LoggingFeature()));
sf.setResourceProvider(HeaderSetResource.class, new
SingletonResourceProvider(resourceMock, true));
sf.setAddress(address);
server = sf.create();
}

@Test
public void multipleHeadersShouldWorkWithProxy() {
final Set<String> names = new HashSet<>(Arrays.asList("foo",
"bar", "baz"));
clientProxy().sayHello(names);
verify(resourceMock).sayHello(names);
}

@Test
public void multipleHeadersShouldWorkWithWebTarget() {
final Set<String> names = new HashSet<>(Arrays.asList("foo",
"bar", "baz"));
callHello(names);
verify(resourceMock).sayHello(names);
}

@Test
public void singleHeadersShouldWorkWithProxy() {
final Set<String> names = Collections.singleton("foo");
clientProxy().sayHello(names);
verify(resourceMock).sayHello(names);
}

@Test
public void singleHeadersShouldWorkWithWebTarget() {
final Set<String> names = Collections.singleton("foo");
callHello(names);
verify(resourceMock).sayHello(names);
}

@After
public void stopServer() {
server.stop();
server.destroy();
}

public WebTarget webTarget() {
final ClientBuilder builder = ClientBuilder.newBuilder();
builder.register(new LoggingFeature());
return builder.build()
.property(AsyncHTTPConduit.USE_ASYNC, Boolean.TRUE)
.target(address);
}
}
Andy McCright
2018-10-04 19:54:24 UTC
Permalink
Hi James,

What is the failure message/stack trace/etc. that you are seeing? I'm not
too familiar with Mockito, but I don't see anywhere where the resource
class returns anything. Possibly that is the problem?

Also, did these tests previously work and recently started failing? I have
been making some changes in this area in order to support the MicroProfile
Rest Client - it's possible I regressed something.

Thanks,

Andy
Post by James Carman
@Path("/")
public interface HeaderSetResource {
@GET
@Path("/hello")
@Produces(TEXT_PLAIN)
}
@RunWith(MockitoJUnitRunner.class)
public class HeaderSetTest {
@Mock
private HeaderSetResource resourceMock;
private Server server;
private String address;
private void callHello(Set<String> names) {
final Invocation.Builder builder =
webTarget().path("hello").request();
names.forEach(name -> builder.header("names", name));
builder.get();
}
public HeaderSetResource clientProxy() {
final JAXRSClientFactoryBean factoryBean = new
JAXRSClientFactoryBean();
factoryBean.setFeatures(Collections.singletonList(new
LoggingFeature()));
factoryBean.setResourceClass(HeaderSetResource.class);
factoryBean.setAddress(address);
return factoryBean.create(HeaderSetResource.class);
}
@Before
public void createServer() {
String port = "10090";
address = String.format("http://localhost:%s/", port);
final JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
sf.setBus(BusFactory.getDefaultBus(true));
sf.setResourceClasses(HeaderSetResource.class);
sf.setFeatures(Collections.singletonList(new LoggingFeature()));
sf.setResourceProvider(HeaderSetResource.class, new
SingletonResourceProvider(resourceMock, true));
sf.setAddress(address);
server = sf.create();
}
@Test
public void multipleHeadersShouldWorkWithProxy() {
final Set<String> names = new HashSet<>(Arrays.asList("foo",
"bar", "baz"));
clientProxy().sayHello(names);
verify(resourceMock).sayHello(names);
}
@Test
public void multipleHeadersShouldWorkWithWebTarget() {
final Set<String> names = new HashSet<>(Arrays.asList("foo",
"bar", "baz"));
callHello(names);
verify(resourceMock).sayHello(names);
}
@Test
public void singleHeadersShouldWorkWithProxy() {
final Set<String> names = Collections.singleton("foo");
clientProxy().sayHello(names);
verify(resourceMock).sayHello(names);
}
@Test
public void singleHeadersShouldWorkWithWebTarget() {
final Set<String> names = Collections.singleton("foo");
callHello(names);
verify(resourceMock).sayHello(names);
}
@After
public void stopServer() {
server.stop();
server.destroy();
}
public WebTarget webTarget() {
final ClientBuilder builder = ClientBuilder.newBuilder();
builder.register(new LoggingFeature());
return builder.build()
.property(AsyncHTTPConduit.USE_ASYNC, Boolean.TRUE)
.target(address);
}
}
James Carman
2018-10-04 20:54:21 UTC
Permalink
The return isn’t really necessary at all. I’m just verifying that the
parameters are “correct” as they are received in the server
Post by Andy McCright
Hi James,
What is the failure message/stack trace/etc. that you are seeing? I'm not
too familiar with Mockito, but I don't see anywhere where the resource
class returns anything. Possibly that is the problem?
Also, did these tests previously work and recently started failing? I have
been making some changes in this area in order to support the MicroProfile
Rest Client - it's possible I regressed something.
Thanks,
Andy
Post by James Carman
@Path("/")
public interface HeaderSetResource {
@GET
@Path("/hello")
@Produces(TEXT_PLAIN)
}
@RunWith(MockitoJUnitRunner.class)
public class HeaderSetTest {
@Mock
private HeaderSetResource resourceMock;
private Server server;
private String address;
private void callHello(Set<String> names) {
final Invocation.Builder builder =
webTarget().path("hello").request();
names.forEach(name -> builder.header("names", name));
builder.get();
}
public HeaderSetResource clientProxy() {
final JAXRSClientFactoryBean factoryBean = new
JAXRSClientFactoryBean();
factoryBean.setFeatures(Collections.singletonList(new
LoggingFeature()));
factoryBean.setResourceClass(HeaderSetResource.class);
factoryBean.setAddress(address);
return factoryBean.create(HeaderSetResource.class);
}
@Before
public void createServer() {
String port = "10090";
address = String.format("http://localhost:%s/", port);
final JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
sf.setBus(BusFactory.getDefaultBus(true));
sf.setResourceClasses(HeaderSetResource.class);
sf.setFeatures(Collections.singletonList(new LoggingFeature()));
sf.setResourceProvider(HeaderSetResource.class, new
SingletonResourceProvider(resourceMock, true));
sf.setAddress(address);
server = sf.create();
}
@Test
public void multipleHeadersShouldWorkWithProxy() {
final Set<String> names = new HashSet<>(Arrays.asList("foo",
"bar", "baz"));
clientProxy().sayHello(names);
verify(resourceMock).sayHello(names);
}
@Test
public void multipleHeadersShouldWorkWithWebTarget() {
final Set<String> names = new HashSet<>(Arrays.asList("foo",
"bar", "baz"));
callHello(names);
verify(resourceMock).sayHello(names);
}
@Test
public void singleHeadersShouldWorkWithProxy() {
final Set<String> names = Collections.singleton("foo");
clientProxy().sayHello(names);
verify(resourceMock).sayHello(names);
}
@Test
public void singleHeadersShouldWorkWithWebTarget() {
final Set<String> names = Collections.singleton("foo");
callHello(names);
verify(resourceMock).sayHello(names);
}
@After
public void stopServer() {
server.stop();
server.destroy();
}
public WebTarget webTarget() {
final ClientBuilder builder = ClientBuilder.newBuilder();
builder.register(new LoggingFeature());
return builder.build()
.property(AsyncHTTPConduit.USE_ASYNC, Boolean.TRUE)
.target(address);
}
}
Loading...