What kind of issue is this?
I can't get the JaxbConverter to work. I can't tell if I'm missing somethin or if it's broken.
Java 8
build.gradle
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-jaxb:2.5.0'
somewhere in the code
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://www.google.com/alerts/feeds/")
.addConverterFactory(JaxbConverterFactory.create())
.build();
service = retrofit.create(GoogleAlertService.class);
...
Response<GoogleAlertRssFeed> response = request.execute();
...
LOG.info(response.body().toString());
GoogleAlertRssFeed
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "feed", namespace = "http://www.w3.org/2005/Atom")
public class GoogleAlertRssFeed {
@XmlElement(required = true)
public String id;
public GoogleAlertRssFeed() {
}
...
@Override
public String toString() {
return "GoogleAlertRssFeed{" +
"id='" + id + '\'' +
'}';
}
}
And the XML looks like:
<?xml version="1.0" encoding="utf-8"?> <feed xmlns="http://www.w3.org/2005/Atom" xmlns:idx="urn:atom-extension:indexing"> <id>tag:google.com,2005:reader/user/xyz/state/com.google/alerts/xyz</id> <title>...
But despite the correct raw response the id is always null.
I tried anything I could find on the net.
@XmlAccessorType(XmlAccessType.FIELD) on the class.@XmlAccessorType(XmlAccessType.FIELD).@XmlElement(name = "id").What am I doing wrong?
Resources:
Try editing JaxbConverterFactoryTest.java, setting it's model type to your model type and it's XML to your XML? If that fails set some breakpoints?
Replaced the test's XML with
static final String SAMPLE_CONTACT_XML = "<?xml version=\"1.0\" encoding=\"utf-8\"?> <feed xmlns=\"http://www.w3.org/2005/Atom\" xmlns:idx=\"urn:atom-extension:indexing\"> <id>tag:google.com,2005:reader/user/abc/state/com.google/alerts/abc</id> </feed> ";
static final Feed SAMPLE_CONTACT = new Feed("tag:google.com,2005:reader/user/abc/state/com.google/alerts/abc");
Replace Contact with Feed:
package retrofit2.converter.jaxb;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "feed")
final class Feed {
@XmlElement(required = true)
public final String id;
@SuppressWarnings("unused") // Used by JAXB.
private Feed() {
this("");
}
public Feed(String id) {
this.id = id;
}
@Override public boolean equals(Object o) {
return o instanceof Feed
&& ((Feed) o).id.equals(id);
}
@Override public int hashCode() {
return Arrays.asList(id).hashCode();
}
}
Changed occurrences of Contact with Feed, name with id and Jenny with tag:google.com,2005:reader/user/abc/state/com.google/alerts/abc in JaxbConverterFactoryTest.java.
Results:
Test set: retrofit2.converter.jaxb.JaxbConverterFactoryTest
-------------------------------------------------------------------------------
Tests run: 6, Failures: 3, Errors: 0, Skipped: 0, Time elapsed: 0.695 sec <<< FAILURE!
userSuppliedJaxbContext(retrofit2.converter.jaxb.JaxbConverterFactoryTest) Time elapsed: 0.052 sec <<< FAILURE!
org.junit.ComparisonFailure: expected:<...<?xml version="1.0" [encoding="utf-8"?> <feed xmlns="http://www.w3.org/2005/Atom" xmlns:idx="urn:atom-extension:indexing"> <id>tag:google.com,2005:reader/user/abc/state/com.google/alerts/abc</id> </feed> ]"> but was:<...<?xml version="1.0" [?><feed><id>tag:google.com,2005:reader/user/abc/state/com.google/alerts/abc</id></feed>]">
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at retrofit2.converter.jaxb.JaxbConverterFactoryTest.userSuppliedJaxbContext(JaxbConverterFactoryTest.java:107)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:48)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
xmlResponseBody(retrofit2.converter.jaxb.JaxbConverterFactoryTest) Time elapsed: 0.019 sec <<< FAILURE!
org.junit.ComparisonFailure: expected:<...converter.jaxb.Feed@[bc1e4518]> but was:<...converter.jaxb.Feed@[1f]>
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at retrofit2.converter.jaxb.JaxbConverterFactoryTest.xmlResponseBody(JaxbConverterFactoryTest.java:88)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:48)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
xmlRequestBody(retrofit2.converter.jaxb.JaxbConverterFactoryTest) Time elapsed: 0.012 sec <<< FAILURE!
org.junit.ComparisonFailure: expected:<...<?xml version="1.0" [encoding="utf-8"?> <feed xmlns="http://www.w3.org/2005/Atom" xmlns:idx="urn:atom-extension:indexing"> <id>tag:google.com,2005:reader/user/abc/state/com.google/alerts/abc</id> </feed> ]"> but was:<...<?xml version="1.0" [?><feed><id>tag:google.com,2005:reader/user/abc/state/com.google/alerts/abc</id></feed>]">
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at retrofit2.converter.jaxb.JaxbConverterFactoryTest.xmlRequestBody(JaxbConverterFactoryTest.java:79)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:48)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
What I can see is that the tags' attributes are missing.
Are you saying that this is a bug in Retrofit's converter? Does it work when using JAXB directly with Strings without Retrofit?
@JakeWharton I don't know whether it's a bug or not. Maybe I'm just stupid.
I now did:
Feed f = JAXB.unmarshal(new StringReader(SAMPLE_CONTACT_XML), Feed.class);
System.out.println("XXX");
System.out.println(f.id);
System.out.println("XXX");
assertThat(f).isEqualTo(SAMPLE_CONTACT);
and it fails, f.id is empty:
Running retrofit2.converter.jaxb.JaxbConverterFactoryTest
XXX
XXX
After removing xmlns="http://www.w3.org/2005/Atom" xmlns:idx="urn:atom-extension:indexing" from the feed tag it works.
Seems to be a namespace issue.
Thought I'd extend the JAXBConverterFactory but JaxbRequestConverter can't be extended :/
And JaxbConverterFactory is final 馃槂 馃敨
Ain't seem to be an issue with retrofit but with JAXB.
Couldn't manage to get it working with (empty) namespace so I'll filter the namespace from the responses:
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
clientBuilder.
addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Response response = chain.proceed(request);
ResponseBody body = response.body();
// filter response here
ResponseBody newBody = ResponseBody.create(MediaType.parse("application/xml"), "<?xml version=\"1.0\" encoding=\"utf-8\"?> <feed> <id>xyz</id> </feed>");
response = (new Response.Builder())
.body(newBody)
.code(response.code())
.headers(response.headers())
.message(response.message())
.protocol(response.protocol())
.receivedResponseAtMillis(response.receivedResponseAtMillis())
.request(response.request())
.build();
return response;
}
});
Most helpful comment
After removing
xmlns="http://www.w3.org/2005/Atom" xmlns:idx="urn:atom-extension:indexing"from the feed tag it works.Seems to be a namespace issue.