[
https://issues.apache.org/jira/browse/CXF-8556?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Noah Rickles updated CXF-8556:
------------------------------
Description:
A service in question needs to be reachable via multiple paths. The `@Path`
param allows for regex matching on a class-level like the following:
`@Path("/\{a:cat|dog}";`. The class in which this annotation is used will
correctly take requests at either `/cat` or `/dog`. A class-level `@PathParam`
is created by the name of `a`.
The issue comes when creating a proxy for this service through the
`JAXRSClientFactoryBean.java` create method shown below:
{code:java}
// @param varValues optional list of values which will be used to substitute
// template variables specified in the class-level JAX-RS Path
annotations
public <T> T create(Class<T> cls, Object... varValues)
{ return cls.cast(createWithValues(varValues)); }{code}
To define the value of the `@PathParam a` that this proxy should use, it
appears as if the `Object... varValues` needs to be populated. The
`ClientProxy` will be created with the following, after the `ClientState` is
retrieved:
{code:java}
protected ClientProxyImpl createClientProxy(ClassResourceInfo cri, boolean
isRoot, ClientState actualState, Object[] varValues) {
if (actualState == null) {
return new ClientProxyImpl(URI.create(getAddress()), proxyLoader, cri,
isRoot, inheritHeaders, getProperties(), varValues);
} else {
return new ClientProxyImpl(actualState, proxyLoader, cri, isRoot,
inheritHeaders, getProperties(), varValues);
}
}
{code}
In this scenario, `actualState` is defined, and `getProperties()` returns
`null`. `varValues` is populated with `\{"dog"}`. The constructor for the
`ClientProxyImpl` in this situation is:
{code:java}
public ClientProxyImpl(ClientState initialState,
ClassLoader loader,
ClassResourceInfo cri,
boolean isRoot,
boolean inheritHeaders,
Object... varValues) { ... }
{code}
The key here is that the result of `getProperties()` will be the first entry in
the `Object[]` created by the var args.
After the `initValuesMap(Object... varValues)` is called, I would expect the
`valuesMap` to have one entry, a mapping of "a" to "dog" so that when the proxy
is used, it will populate the `@PathParam a` with "dog" automatically. What
ends up happening is because the `null` `properties` is being passed as part of
the `Object... varValues` to the `ClientProxyImpl` constructor, the `varValues`
turns into an array of [null, "dog"] instead of the expected `["dog"]`. The
proxy creates successfully but does not work because the `valuesMap` ends up
mapping "a" to `null`. This breaks the URI builder implementation with an
`IllegalArgumentException`:
{code:java}
private URI doBuild(boolean fromEncoded, boolean encodePathSlash, Object...
values) {
if (values == null)
{ throw new IllegalArgumentException("Template parameter values are set to
null"); }
for (int i = 0; i < values.length; i++) {
if (values[i] == null)
{ throw new IllegalArgumentException("Template parameter value at position " +
i + " is set to null"); }
}
...
}
{code}
A change to the `createClientProxy` method was made here:
[https://github.com/apache/cxf/pull/572|https://github.com/apache/cxf/pull/572.]
and maybe needs to be addressed.
was:
A service in question needs to be reachable via multiple paths. The `@Path`
param allows for regex matching on a class-level like the following:
`@Path("/\{a:cat|dog}";`. The class in which this annotation is used will
correctly take requests at either `/cat` or `/dog`. A class-level `@PathParam`
is created by the name of `a`.
The issue comes when creating a proxy for this service through the
`JAXRSClientFactoryBean.java` create method shown below:
```
* @param varValues optional list of values which will be used to substitute
* template variables specified in the class-level JAX-RS Path annotations
public <T> T create(Class<T> cls, Object... varValues) {
return cls.cast(createWithValues(varValues));
}
```
To define the value of the `@PathParam a` that this proxy should use, it
appears as if the `Object... varValues` needs to be populated. The
`ClientProxy` will be created with the following, after the `ClientState` is
retrieved:
```
protected ClientProxyImpl createClientProxy(ClassResourceInfo cri, boolean
isRoot,
ClientState actualState, Object[] varValues) {
if (actualState == null) {
return new ClientProxyImpl(URI.create(getAddress()), proxyLoader, cri,
isRoot,
inheritHeaders, getProperties(), varValues);
} else {
return new ClientProxyImpl(actualState, proxyLoader, cri, isRoot,
inheritHeaders, getProperties(), varValues);
}
}
```
In this scenario, `actualState` is defined, and `getProperties()` returns
`null`. `varValues` is populated with `\{"dog"}`. The constructor for the
`ClientProxyImpl` in this situation is:
```
public ClientProxyImpl(ClientState initialState,
ClassLoader loader,
ClassResourceInfo cri,
boolean isRoot,
boolean inheritHeaders,
Object... varValues) \{ ... }
```
The key here is that the result of `getProperties()` will be the first entry in
the `Object[]` created by the var args.
After the `initValuesMap(Object... varValues)` is called, I would expect the
`valuesMap` to have one entry, a mapping of "a" to "dog" so that when the proxy
is used, it will populate the `@PathParam a` with "dog" automatically. What
ends up happening is because the `null` `properties` is being passed as part of
the `Object... varValues` to the `ClientProxyImpl` constructor, the `varValues`
turns into an array of [null, "dog"] instead of the expected `["dog"]`. The
proxy creates successfully but does not work because the `valuesMap` ends up
mapping "a" to `null`. This breaks the URI builder implementation with an
`IllegalArgumentException`:
```
private URI doBuild(boolean fromEncoded, boolean encodePathSlash, Object...
values) {
if (values == null) {
throw new IllegalArgumentException("Template parameter values are set to
null");
}
for (int i = 0; i < values.length; i++) {
if (values[i] == null) {
throw new IllegalArgumentException("Template parameter value at position " + i
+ " is set to null");
}
}
...
}
A change to the `createClientProxy` method was made here:
[https://github.com/apache/cxf/pull/572|https://github.com/apache/cxf/pull/572.]
and needs to be addressed.
> Null AbstractEndpointFactory Properties Interferes with Class-Level PathParam
> When Creating Proxies with Defined ClientState
> ----------------------------------------------------------------------------------------------------------------------------
>
> Key: CXF-8556
> URL: https://issues.apache.org/jira/browse/CXF-8556
> Project: CXF
> Issue Type: Bug
> Components: JAX-RS
> Affects Versions: 3.4.4
> Reporter: Noah Rickles
> Priority: Major
> Labels: Bug
>
> A service in question needs to be reachable via multiple paths. The `@Path`
> param allows for regex matching on a class-level like the following:
> `@Path("/\{a:cat|dog}";`. The class in which this annotation is used will
> correctly take requests at either `/cat` or `/dog`. A class-level
> `@PathParam` is created by the name of `a`.
>
> The issue comes when creating a proxy for this service through the
> `JAXRSClientFactoryBean.java` create method shown below:
> {code:java}
> // @param varValues optional list of values which will be used to substitute
> // template variables specified in the class-level JAX-RS
> Path annotations
> public <T> T create(Class<T> cls, Object... varValues)
> { return cls.cast(createWithValues(varValues)); }{code}
> To define the value of the `@PathParam a` that this proxy should use, it
> appears as if the `Object... varValues` needs to be populated. The
> `ClientProxy` will be created with the following, after the `ClientState` is
> retrieved:
> {code:java}
> protected ClientProxyImpl createClientProxy(ClassResourceInfo cri, boolean
> isRoot, ClientState actualState, Object[] varValues) {
> if (actualState == null) {
> return new ClientProxyImpl(URI.create(getAddress()), proxyLoader,
> cri, isRoot, inheritHeaders, getProperties(), varValues);
> } else {
> return new ClientProxyImpl(actualState, proxyLoader, cri, isRoot,
> inheritHeaders, getProperties(), varValues);
> }
> }
> {code}
> In this scenario, `actualState` is defined, and `getProperties()` returns
> `null`. `varValues` is populated with `\{"dog"}`. The constructor for the
> `ClientProxyImpl` in this situation is:
> {code:java}
> public ClientProxyImpl(ClientState initialState,
> ClassLoader loader,
> ClassResourceInfo cri,
> boolean isRoot,
> boolean inheritHeaders,
> Object... varValues) { ... }
> {code}
> The key here is that the result of `getProperties()` will be the first entry
> in the `Object[]` created by the var args.
> After the `initValuesMap(Object... varValues)` is called, I would expect the
> `valuesMap` to have one entry, a mapping of "a" to "dog" so that when the
> proxy is used, it will populate the `@PathParam a` with "dog" automatically.
> What ends up happening is because the `null` `properties` is being passed as
> part of the `Object... varValues` to the `ClientProxyImpl` constructor, the
> `varValues` turns into an array of [null, "dog"] instead of the expected
> `["dog"]`. The proxy creates successfully but does not work because the
> `valuesMap` ends up mapping "a" to `null`. This breaks the URI builder
> implementation with an `IllegalArgumentException`:
> {code:java}
> private URI doBuild(boolean fromEncoded, boolean encodePathSlash, Object...
> values) {
> if (values == null)
> { throw new IllegalArgumentException("Template parameter values are set to
> null"); }
> for (int i = 0; i < values.length; i++) {
> if (values[i] == null)
> { throw new IllegalArgumentException("Template parameter value at position "
> + i + " is set to null"); }
> }
> ...
> }
> {code}
>
>
> A change to the `createClientProxy` method was made here:
> [https://github.com/apache/cxf/pull/572|https://github.com/apache/cxf/pull/572.]
> and maybe needs to be addressed.
--
This message was sent by Atlassian Jira
(v8.3.4#803005)