Skip to content

Commit 81897db

Browse files
authored
Add serialization format support to annotation-processor (Azure#44609)
1 parent 8bb8cd7 commit 81897db

File tree

18 files changed

+745
-295
lines changed

18 files changed

+745
-295
lines changed

eng/versioning/version_client.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,8 @@ io.clientcore:annotation-processor-test;1.0.0-beta.1;1.0.0-beta.1
493493
# In the pom, the version update tag after the version should name the unreleased package and the dependency version:
494494
# <!-- {x-version-update;unreleased_com.azure:azure-core;dependency} -->
495495

496+
unreleased_io.clientcore:core;1.0.0-beta.8
497+
unreleased_io.clientcore:annotation-processor;1.0.0-beta.2
496498
unreleased_com.azure.v2:azure-core;2.0.0-beta.1
497499

498500
# Released Beta dependencies: Copy the entry from above, prepend "beta_", remove the current

sdk/clientcore/annotation-processor-test/pom.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
<dependency>
5656
<groupId>io.clientcore</groupId>
5757
<artifactId>core</artifactId>
58-
<version>1.0.0-beta.7</version> <!-- {x-version-update;io.clientcore:core;dependency} -->
58+
<version>1.0.0-beta.8</version> <!-- {x-version-update;unreleased_io.clientcore:core;dependency} -->
5959
</dependency>
6060
<dependency>
6161
<groupId>io.clientcore</groupId>
@@ -67,7 +67,7 @@
6767
<dependency>
6868
<groupId>io.clientcore</groupId>
6969
<artifactId>core</artifactId>
70-
<version>1.0.0-beta.7</version> <!-- {x-version-update;io.clientcore:core;dependency} -->
70+
<version>1.0.0-beta.8</version> <!-- {x-version-update;unreleased_io.clientcore:core;dependency} -->
7171
<type>test-jar</type>
7272
<scope>test</scope>
7373
</dependency>
@@ -130,7 +130,7 @@
130130
<annotationProcessorPath>
131131
<groupId>io.clientcore</groupId>
132132
<artifactId>annotation-processor</artifactId>
133-
<version>1.0.0-beta.1</version> <!-- {x-version-update;unreleased_io.clientcore:annotation-processor;dependency} -->
133+
<version>1.0.0-beta.2</version> <!-- {x-version-update;unreleased_io.clientcore:annotation-processor;dependency} -->
134134
</annotationProcessorPath>
135135
</annotationProcessorPaths>
136136
<annotationProcessors>
@@ -148,7 +148,7 @@
148148
<dependency>
149149
<groupId>io.clientcore</groupId>
150150
<artifactId>annotation-processor</artifactId>
151-
<version>1.0.0-beta.1</version> <!-- {x-version-update;unreleased_io.clientcore:annotation-processor;dependency} -->
151+
<version>1.0.0-beta.2</version> <!-- {x-version-update;unreleased_io.clientcore:annotation-processor;dependency} -->
152152
</dependency>
153153
</dependencies>
154154
</plugin>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package io.clientcore.annotation.processor.test.implementation;
2+
3+
import io.clientcore.annotation.processor.test.implementation.models.SimpleXmlSerializable;
4+
import io.clientcore.core.annotations.ServiceInterface;
5+
import io.clientcore.core.http.annotations.BodyParam;
6+
import io.clientcore.core.http.annotations.HeaderParam;
7+
import io.clientcore.core.http.annotations.HttpRequestInformation;
8+
import io.clientcore.core.http.models.HttpMethod;
9+
import io.clientcore.core.http.pipeline.HttpPipeline;
10+
11+
import java.lang.reflect.InvocationTargetException;
12+
13+
/**
14+
* Service interface for handling XML serialization and deserialization.
15+
*/
16+
@ServiceInterface(name = "XmlSerializable", host = "http://localhost")
17+
public interface SimpleXmlSerializableService {
18+
19+
/**
20+
* Creates a new instance of the SimpleXmlSerializableService.
21+
*
22+
* @param pipeline The HTTP pipeline to be used by the service.
23+
* @return A new instance of SimpleXmlSerializableService.
24+
* @throws IllegalArgumentException if the pipeline is null.
25+
* @throws RuntimeException if there is an error creating the service instance.
26+
*/
27+
static SimpleXmlSerializableService getNewInstance(HttpPipeline pipeline) {
28+
if (pipeline == null) {
29+
throw new IllegalArgumentException("pipeline cannot be null");
30+
}
31+
try {
32+
Class<?> clazz = Class.forName("io.clientcore.annotation.processor.test.SimpleXmlSerializableServiceImpl");
33+
return (SimpleXmlSerializableService) clazz
34+
.getMethod("getNewInstance", HttpPipeline.class)
35+
.invoke(null, pipeline);
36+
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException
37+
| InvocationTargetException e) {
38+
throw new RuntimeException(e);
39+
}
40+
}
41+
42+
/**
43+
* Sends an XML payload with the content type "application/xml".
44+
*
45+
* @param simpleXmlSerializable The XML payload to be sent.
46+
*/
47+
@HttpRequestInformation(method = HttpMethod.PUT, path = "sendApplicationXml", expectedStatusCodes = { 200 })
48+
void sendApplicationXml(@BodyParam("application/xml") SimpleXmlSerializable simpleXmlSerializable);
49+
50+
/**
51+
* Sends an XML payload with the content type "text/xml".
52+
*
53+
* @param simpleXmlSerializable The XML payload to be sent.
54+
*/
55+
@HttpRequestInformation(method = HttpMethod.PUT, path = "sendTextXml", expectedStatusCodes = { 200 })
56+
void sendTextXml(@BodyParam("text/xml") SimpleXmlSerializable simpleXmlSerializable);
57+
58+
/**
59+
* Retrieves an XML payload.
60+
*
61+
* @param contentType The content type of the XML payload.
62+
* @return The retrieved XML payload.
63+
*/
64+
@HttpRequestInformation(method = HttpMethod.GET, path = "getXml", expectedStatusCodes = { 200 })
65+
SimpleXmlSerializable getXml(@HeaderParam("Content-Type") String contentType);
66+
67+
/**
68+
* Retrieves an invalid XML payload.
69+
*
70+
* @return The retrieved invalid XML payload.
71+
*/
72+
@HttpRequestInformation(method = HttpMethod.GET, path = "getInvalidXml", expectedStatusCodes = { 200 })
73+
SimpleXmlSerializable getInvalidXml();
74+
}

sdk/clientcore/annotation-processor-test/src/main/java/io/clientcore/annotation/processor/test/implementation/TestInterfaceClientImpl.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import io.clientcore.core.http.pipeline.HttpPipeline;
2121
import io.clientcore.core.implementation.http.ContentType;
2222
import io.clientcore.core.models.binarydata.BinaryData;
23-
import io.clientcore.core.serialization.ObjectSerializer;
23+
2424
import java.io.InputStream;
2525
import java.lang.reflect.InvocationTargetException;
2626
import java.nio.ByteBuffer;
@@ -33,15 +33,15 @@ public final class TestInterfaceClientImpl {
3333

3434
@ServiceInterface(name = "myService")
3535
public interface TestInterfaceClientService {
36-
static TestInterfaceClientService getNewInstance(HttpPipeline pipeline, ObjectSerializer serializer) {
36+
static TestInterfaceClientService getNewInstance(HttpPipeline pipeline) {
3737
if (pipeline == null) {
3838
throw new IllegalArgumentException("pipeline cannot be null");
3939
}
4040
try {
4141
Class<?> clazz = Class.forName("io.clientcore.annotation.processor.test.implementation.TestInterfaceClientServiceImpl");
4242
return (TestInterfaceClientService) clazz
43-
.getMethod("getNewInstance", HttpPipeline.class, ObjectSerializer.class)
44-
.invoke(null, pipeline, serializer);
43+
.getMethod("getNewInstance", HttpPipeline.class)
44+
.invoke(null, pipeline);
4545
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException
4646
| InvocationTargetException e) {
4747
throw new RuntimeException(e);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package io.clientcore.annotation.processor.test.implementation.models;
5+
6+
import io.clientcore.core.serialization.xml.XmlReader;
7+
import io.clientcore.core.serialization.xml.XmlSerializable;
8+
import io.clientcore.core.serialization.xml.XmlToken;
9+
import io.clientcore.core.serialization.xml.XmlWriter;
10+
import io.clientcore.core.utils.CoreUtils;
11+
12+
import javax.xml.stream.XMLStreamException;
13+
import java.util.Objects;
14+
15+
/**
16+
* Test class implementing {@link XmlSerializable}.
17+
*/
18+
public final class SimpleXmlSerializable implements XmlSerializable<SimpleXmlSerializable> {
19+
private final boolean aBooleanAsAttribute;
20+
private final int anInt;
21+
private final double aDecimalAsAttribute;
22+
private final String aString;
23+
24+
public SimpleXmlSerializable(boolean aBooleanAsAttribute, int anInt, double aDecimalAsAttribute, String aString) {
25+
this.aBooleanAsAttribute = aBooleanAsAttribute;
26+
this.anInt = anInt;
27+
this.aDecimalAsAttribute = aDecimalAsAttribute;
28+
this.aString = aString;
29+
}
30+
31+
@Override
32+
public XmlWriter toXml(XmlWriter xmlWriter) throws XMLStreamException {
33+
return toXml(xmlWriter, null);
34+
}
35+
36+
@Override
37+
public XmlWriter toXml(XmlWriter xmlWriter, String rootElementName) throws XMLStreamException {
38+
rootElementName = CoreUtils.isNullOrEmpty(rootElementName) ? "SimpleXml" : rootElementName;
39+
xmlWriter.writeStartElement(rootElementName);
40+
41+
xmlWriter.writeBooleanAttribute("boolean", aBooleanAsAttribute);
42+
xmlWriter.writeDoubleAttribute("decimal", aDecimalAsAttribute);
43+
44+
xmlWriter.writeIntElement("int", anInt);
45+
xmlWriter.writeStringElement("string", aString);
46+
47+
return xmlWriter.writeEndElement();
48+
}
49+
50+
public static SimpleXmlSerializable fromXml(XmlReader xmlReader) throws XMLStreamException {
51+
return fromXml(xmlReader, null);
52+
}
53+
54+
public static SimpleXmlSerializable fromXml(XmlReader xmlReader, String rootElementName) throws XMLStreamException {
55+
rootElementName = CoreUtils.isNullOrEmpty(rootElementName) ? "SimpleXml" : rootElementName;
56+
return xmlReader.readObject(rootElementName, reader -> {
57+
boolean aBooleanAsAttribute = xmlReader.getBooleanAttribute(null, "boolean");
58+
double aDecimalAsAttribute = xmlReader.getDoubleAttribute(null, "decimal");
59+
int anInt = 0;
60+
boolean foundAnInt = false;
61+
String aString = null;
62+
boolean foundAString = false;
63+
64+
while (xmlReader.nextElement() != XmlToken.END_ELEMENT) {
65+
String elementName = xmlReader.getElementName().getLocalPart();
66+
if ("int".equals(elementName)) {
67+
anInt = xmlReader.getIntElement();
68+
foundAnInt = true;
69+
} else if ("string".equals(elementName)) {
70+
aString = xmlReader.getStringElement();
71+
foundAString = true;
72+
} else {
73+
xmlReader.skipElement();
74+
}
75+
}
76+
77+
if (foundAnInt && foundAString) {
78+
return new SimpleXmlSerializable(aBooleanAsAttribute, anInt, aDecimalAsAttribute, aString);
79+
}
80+
81+
throw new IllegalStateException("Missing required elements.");
82+
});
83+
}
84+
85+
public boolean isABoolean() {
86+
return aBooleanAsAttribute;
87+
}
88+
89+
public int getAnInt() {
90+
return anInt;
91+
}
92+
93+
public double getADecimal() {
94+
return aDecimalAsAttribute;
95+
}
96+
97+
public String getAString() {
98+
return aString;
99+
}
100+
101+
@Override
102+
public int hashCode() {
103+
return Objects.hash(aBooleanAsAttribute, anInt, aDecimalAsAttribute, aString);
104+
}
105+
106+
@Override
107+
public boolean equals(Object obj) {
108+
if (!(obj instanceof SimpleXmlSerializable)) {
109+
return false;
110+
}
111+
112+
SimpleXmlSerializable other = (SimpleXmlSerializable) obj;
113+
114+
return aBooleanAsAttribute == other.aBooleanAsAttribute
115+
&& anInt == other.anInt
116+
&& aDecimalAsAttribute == other.aDecimalAsAttribute
117+
&& Objects.equals(aString, other.aString);
118+
}
119+
}

sdk/clientcore/annotation-processor-test/src/test/java/io/clientcore/annotation/processor/test/PagingOperationTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public void testListFoo() {
5454
return new MockHttpResponse(request, 404);
5555
})
5656
.build();
57-
TestInterfaceClientService testInterface = TestInterfaceClientService.getNewInstance(pipeline, null);
57+
TestInterfaceClientService testInterface = TestInterfaceClientService.getNewInstance(pipeline);
5858

5959
// Retrieve initial response
6060
Response<List<Foo>> initialResponse = testInterface.listFoo(uri, null, RequestOptions.none());
@@ -103,7 +103,7 @@ public void testListFooListResult() {
103103
})
104104
.build();
105105

106-
TestInterfaceClientService testInterface = TestInterfaceClientService.getNewInstance(pipeline, null);
106+
TestInterfaceClientService testInterface = TestInterfaceClientService.getNewInstance(pipeline);
107107

108108
// Fetch the first page
109109
PagedIterable<Foo> pagedIterable = new PagedIterable<>(

sdk/clientcore/annotation-processor-test/src/test/java/io/clientcore/annotation/processor/test/RestProxyTests.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import io.clientcore.core.http.pipeline.HttpPipelineBuilder;
1111
import io.clientcore.core.implementation.http.ContentType;
1212
import io.clientcore.core.models.binarydata.BinaryData;
13-
import io.clientcore.core.serialization.json.JsonSerializer;
1413
import org.junit.jupiter.api.Named;
1514
import org.junit.jupiter.api.Test;
1615
import org.junit.jupiter.params.ParameterizedTest;
@@ -39,8 +38,7 @@ public void contentTypeHeaderPriorityOverBodyParamAnnotationTest() throws IOExce
3938
HttpPipeline pipeline = new HttpPipelineBuilder().httpClient(client).build();
4039

4140
TestInterfaceClientImpl.TestInterfaceClientService testInterface =
42-
TestInterfaceClientImpl.TestInterfaceClientService.getNewInstance(pipeline,
43-
new JsonSerializer());
41+
TestInterfaceClientImpl.TestInterfaceClientService.getNewInstance(pipeline);
4442
byte[] bytes = "hello".getBytes();
4543
try (Response<Void> response
4644
= testInterface.testMethod(ByteBuffer.wrap(bytes), "application/json", (long) bytes.length)) {
@@ -56,7 +54,7 @@ public void streamResponseShouldHaveHttpResponseReference() {
5654
.httpClient(client)
5755
.build();
5856
TestInterfaceClientImpl.TestInterfaceClientService testInterface =
59-
TestInterfaceClientImpl.TestInterfaceClientService.getNewInstance(pipeline, new JsonSerializer());
57+
TestInterfaceClientImpl.TestInterfaceClientService.getNewInstance(pipeline);
6058
StreamResponse streamResponse = testInterface.testDownload();
6159
6260
streamResponse.close();
@@ -72,7 +70,7 @@ public void knownLengthBinaryDataIsPassthrough(BinaryData data, long contentLeng
7270
HttpPipeline pipeline = new HttpPipelineBuilder().httpClient(client).build();
7371

7472
TestInterfaceClientImpl.TestInterfaceClientService testInterface =
75-
TestInterfaceClientImpl.TestInterfaceClientService.getNewInstance(pipeline, new JsonSerializer());
73+
TestInterfaceClientImpl.TestInterfaceClientService.getNewInstance(pipeline);
7674
Response<Void> response = testInterface.testMethod(data, "application/json", contentLength);
7775

7876
assertEquals(200, response.getStatusCode());
@@ -102,7 +100,7 @@ public void doesNotChangeBinaryDataContentType(BinaryData data, long contentLeng
102100
Class<? extends BinaryData> expectedContentClazz = data.getClass();
103101

104102
TestInterfaceClientImpl.TestInterfaceClientService testInterface =
105-
TestInterfaceClientImpl.TestInterfaceClientService.getNewInstance(pipeline, new JsonSerializer());
103+
TestInterfaceClientImpl.TestInterfaceClientService.getNewInstance(pipeline);
106104
Response<Void> response = testInterface.testMethod(data, ContentType.APPLICATION_JSON, contentLength);
107105

108106
assertEquals(200, response.getStatusCode());
@@ -118,7 +116,7 @@ public void voidReturningApiClosesResponse() {
118116
HttpPipeline pipeline = new HttpPipelineBuilder().httpClient(client).build();
119117

120118
TestInterfaceClientImpl.TestInterfaceClientService testInterface =
121-
TestInterfaceClientImpl.TestInterfaceClientService.getNewInstance(pipeline, new JsonSerializer());
119+
TestInterfaceClientImpl.TestInterfaceClientService.getNewInstance(pipeline);
122120

123121
testInterface.testMethodReturnsVoid();
124122

@@ -155,7 +153,7 @@ public void doesNotChangeEncodedPath() throws IOException {
155153
}).build();
156154

157155
TestInterfaceClientImpl.TestInterfaceClientService testInterface =
158-
TestInterfaceClientImpl.TestInterfaceClientService.getNewInstance(pipeline, new JsonSerializer());
156+
TestInterfaceClientImpl.TestInterfaceClientService.getNewInstance(pipeline);
159157

160158
testInterface.testListNext(nextLinkUri).close();
161159
}

sdk/clientcore/annotation-processor-test/src/test/java/io/clientcore/annotation/processor/test/TestInterfaceGenerationTests.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public void testGetNewInstance() {
4444
HttpPipeline pipeline = new HttpPipelineBuilder().httpClient(client).build();
4545

4646
TestInterfaceClientImpl.TestInterfaceClientService testInterface =
47-
TestInterfaceClientImpl.TestInterfaceClientService.getNewInstance(pipeline, null);
47+
TestInterfaceClientImpl.TestInterfaceClientService.getNewInstance(pipeline);
4848
assertNotNull(testInterface);
4949
}
5050

@@ -58,7 +58,7 @@ public void testGetFoo() {
5858
new MockHttpResponse(request, 200, BinaryData.fromString(wireValue))).build();
5959

6060
TestInterfaceClientImpl.TestInterfaceClientService testInterface =
61-
TestInterfaceClientImpl.TestInterfaceClientService.getNewInstance(pipeline, null);
61+
TestInterfaceClientImpl.TestInterfaceClientService.getNewInstance(pipeline);
6262
assertNotNull(testInterface);
6363

6464
// test getFoo method
@@ -80,7 +80,7 @@ public void testGetFoo() {
8080
public void requestWithByteArrayReturnType() {
8181
HttpPipeline pipeline = new HttpPipelineBuilder().httpClient(getHttpClient()).build();
8282
TestInterfaceClientImpl.TestInterfaceClientService testInterface =
83-
TestInterfaceClientImpl.TestInterfaceClientService.getNewInstance(pipeline, null);
83+
TestInterfaceClientImpl.TestInterfaceClientService.getNewInstance(pipeline);
8484
final byte[] result = testInterface.getByteArray(getServerUri(false));
8585

8686
assertNotNull(result);
@@ -96,7 +96,7 @@ public void requestWithByteArrayReturnTypeAndParameterizedHostAndPath() {
9696
//https://github.com/Azure/azure-sdk-for-java/issues/44298
9797
HttpPipeline pipeline = new HttpPipelineBuilder().httpClient(getHttpClient()).build();
9898
TestInterfaceClientImpl.TestInterfaceClientService testInterface =
99-
TestInterfaceClientImpl.TestInterfaceClientService.getNewInstance(pipeline, null);
99+
TestInterfaceClientImpl.TestInterfaceClientService.getNewInstance(pipeline);
100100
final byte[] result
101101
= testInterface.getByteArray("http", "localhost:" + server.getHttpPort(), 100);
102102

@@ -111,7 +111,7 @@ public void requestWithByteArrayReturnTypeAndParameterizedHostAndPath() {
111111
public void getRequestWithNoReturn() {
112112
HttpPipeline pipeline = new HttpPipelineBuilder().httpClient(getHttpClient()).build();
113113
TestInterfaceClientImpl.TestInterfaceClientService testInterface =
114-
TestInterfaceClientImpl.TestInterfaceClientService.getNewInstance(pipeline, null);
114+
TestInterfaceClientImpl.TestInterfaceClientService.getNewInstance(pipeline);
115115
assertDoesNotThrow(() -> testInterface.getNothing(getServerUri(false)));
116116
}
117117

0 commit comments

Comments
 (0)