Browse Source

added jaxb-jakarta module on the basis of jaxb module (#2014)

pull/2016/head
FloLei 1 year ago committed by GitHub
parent
commit
057fd463a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 63
      jaxb-jakarta/pom.xml
  2. 20
      jaxb-jakarta/src/main/java/feign/jaxb/JAXBContextCacheKey.java
  3. 43
      jaxb-jakarta/src/main/java/feign/jaxb/JAXBContextClassCacheKey.java
  4. 196
      jaxb-jakarta/src/main/java/feign/jaxb/JAXBContextFactory.java
  5. 52
      jaxb-jakarta/src/main/java/feign/jaxb/JAXBContextInstantationMode.java
  6. 46
      jaxb-jakarta/src/main/java/feign/jaxb/JAXBContextPackageCacheKey.java
  7. 127
      jaxb-jakarta/src/main/java/feign/jaxb/JAXBDecoder.java
  8. 67
      jaxb-jakarta/src/main/java/feign/jaxb/JAXBEncoder.java
  9. 280
      jaxb-jakarta/src/test/java/feign/jaxb/JAXBCodecTest.java
  10. 151
      jaxb-jakarta/src/test/java/feign/jaxb/JAXBContextFactoryTest.java
  11. 161
      jaxb-jakarta/src/test/java/feign/jaxb/examples/AWSSignatureVersion4.java
  12. 90
      jaxb-jakarta/src/test/java/feign/jaxb/examples/IAMExample.java
  13. 16
      jaxb-jakarta/src/test/java/feign/jaxb/examples/package-info.java
  14. 21
      jaxb-jakarta/src/test/java/feign/jaxb/mock/anotherpackage/MockedJAXBObject.java
  15. 25
      jaxb-jakarta/src/test/java/feign/jaxb/mock/anotherpackage/ObjectFactory.java
  16. 21
      jaxb-jakarta/src/test/java/feign/jaxb/mock/onepackage/AnotherMockedJAXBObject.java
  17. 21
      jaxb-jakarta/src/test/java/feign/jaxb/mock/onepackage/MockedJAXBObject.java
  18. 29
      jaxb-jakarta/src/test/java/feign/jaxb/mock/onepackage/ObjectFactory.java

63
jaxb-jakarta/pom.xml

@ -0,0 +1,63 @@ @@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2012-2023 The Feign Authors
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License
is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the License for the specific language governing permissions and limitations under
the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.github.openfeign</groupId>
<artifactId>parent</artifactId>
<version>12.4-SNAPSHOT</version>
</parent>
<artifactId>feign-jaxb-jakarta</artifactId>
<name>Feign JAXB Jakarta</name>
<description>Feign JAXB Jakarta</description>
<properties>
<main.basedir>${project.basedir}/..</main.basedir>
</properties>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>feign-core</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>feign-core</artifactId>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
<version>4.0.0</version>
</dependency>
<!-- Test -->
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>4.0.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

20
jaxb-jakarta/src/main/java/feign/jaxb/JAXBContextCacheKey.java

@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
/*
* Copyright 2012-2023 The Feign Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package feign.jaxb;
/**
* Encapsulate data used to build the cache key of JAXBContext.
*/
interface JAXBContextCacheKey {
}

43
jaxb-jakarta/src/main/java/feign/jaxb/JAXBContextClassCacheKey.java

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
/*
* Copyright 2012-2023 The Feign Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package feign.jaxb;
import java.util.Objects;
/**
* Encapsulate data used to build the cache key of JAXBContext when created using class mode.
*/
final class JAXBContextClassCacheKey implements JAXBContextCacheKey {
private final Class<?> clazz;
JAXBContextClassCacheKey(Class<?> clazz) {
this.clazz = clazz;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
JAXBContextClassCacheKey that = (JAXBContextClassCacheKey) o;
return clazz.equals(that.clazz);
}
@Override
public int hashCode() {
return Objects.hash(clazz);
}
}

196
jaxb-jakarta/src/main/java/feign/jaxb/JAXBContextFactory.java

@ -0,0 +1,196 @@ @@ -0,0 +1,196 @@
/*
* Copyright 2012-2023 The Feign Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package feign.jaxb;
import jakarta.xml.bind.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
/**
* Creates and caches JAXB contexts as well as creates Marshallers and Unmarshallers for each
* context. Since JAXB contexts creation can be an expensive task, JAXB context can be preloaded on
* factory creation otherwise they will be created and cached dynamically when needed.
*/
public final class JAXBContextFactory {
private final ConcurrentHashMap<JAXBContextCacheKey, JAXBContext> jaxbContexts =
new ConcurrentHashMap<>(64);
private final Map<String, Object> properties;
private final JAXBContextInstantationMode jaxbContextInstantationMode;
private JAXBContextFactory(Map<String, Object> properties,
JAXBContextInstantationMode jaxbContextInstantationMode) {
this.properties = properties;
this.jaxbContextInstantationMode = jaxbContextInstantationMode;
}
/**
* Creates a new {@link jakarta.xml.bind.Unmarshaller} that handles the supplied class.
*/
public Unmarshaller createUnmarshaller(Class<?> clazz) throws JAXBException {
return getContext(clazz).createUnmarshaller();
}
/**
* Creates a new {@link jakarta.xml.bind.Marshaller} that handles the supplied class.
*/
public Marshaller createMarshaller(Class<?> clazz) throws JAXBException {
Marshaller marshaller = getContext(clazz).createMarshaller();
setMarshallerProperties(marshaller);
return marshaller;
}
private void setMarshallerProperties(Marshaller marshaller) throws PropertyException {
for (Entry<String, Object> en : properties.entrySet()) {
marshaller.setProperty(en.getKey(), en.getValue());
}
}
private JAXBContext getContext(Class<?> clazz) throws JAXBException {
JAXBContextCacheKey cacheKey = jaxbContextInstantationMode.getJAXBContextCacheKey(clazz);
JAXBContext jaxbContext = this.jaxbContexts.get(cacheKey);
if (jaxbContext == null) {
jaxbContext = jaxbContextInstantationMode.getJAXBContext(clazz);
this.jaxbContexts.putIfAbsent(cacheKey, jaxbContext);
}
return jaxbContext;
}
/**
* Will preload factory's cache with JAXBContext for provided classes
*
* @param classes
* @throws jakarta.xml.bind.JAXBException
*/
private void preloadContextCache(List<Class<?>> classes) throws JAXBException {
if (classes != null && !classes.isEmpty()) {
for (Class<?> clazz : classes) {
getContext(clazz);
}
}
}
/**
* Creates instances of {@link JAXBContextFactory}.
*/
public static class Builder {
private final Map<String, Object> properties = new HashMap<>(10);
private JAXBContextInstantationMode jaxbContextInstantationMode =
JAXBContextInstantationMode.CLASS;
/**
* Sets the jaxb.encoding property of any Marshaller created by this factory.
*/
public Builder withMarshallerJAXBEncoding(String value) {
properties.put(Marshaller.JAXB_ENCODING, value);
return this;
}
/**
* Sets the jaxb.schemaLocation property of any Marshaller created by this factory.
*/
public Builder withMarshallerSchemaLocation(String value) {
properties.put(Marshaller.JAXB_SCHEMA_LOCATION, value);
return this;
}
/**
* Sets the jaxb.noNamespaceSchemaLocation property of any Marshaller created by this factory.
*/
public Builder withMarshallerNoNamespaceSchemaLocation(String value) {
properties.put(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, value);
return this;
}
/**
* Sets the jaxb.formatted.output property of any Marshaller created by this factory.
*/
public Builder withMarshallerFormattedOutput(Boolean value) {
properties.put(Marshaller.JAXB_FORMATTED_OUTPUT, value);
return this;
}
/**
* Sets the jaxb.fragment property of any Marshaller created by this factory.
*/
public Builder withMarshallerFragment(Boolean value) {
properties.put(Marshaller.JAXB_FRAGMENT, value);
return this;
}
/**
* Sets the given property of any Marshaller created by this factory.
*
* <p>
* Example : <br>
* <br>
* <code>
* new JAXBContextFactory.Builder()
* .withProperty("com.sun.xml.internal.bind.xmlHeaders", "&lt;!DOCTYPE Example SYSTEM \&quot;example.dtd\&quot;&gt;")
* .build();
* </code>
* </p>
*/
public Builder withProperty(String key, Object value) {
properties.put(key, value);
return this;
}
/**
* Provide an instantiation mode for JAXB Contexts, can be class or package, default is class if
* this method is not called.
*
* <p>
* Example : <br>
* <br>
* <code>
* new JAXBContextFactory.Builder()
* .withJAXBContextInstantiationMode(JAXBContextInstantationMode.PACKAGE)
* .build();
* </code>
* </p>
*/
public Builder withJAXBContextInstantiationMode(JAXBContextInstantationMode jaxbContextInstantiationMode) {
this.jaxbContextInstantationMode = jaxbContextInstantiationMode;
return this;
}
/**
* Creates a new {@link JAXBContextFactory} instance with a lazy loading cached context
*/
public JAXBContextFactory build() {
return new JAXBContextFactory(properties, jaxbContextInstantationMode);
}
/**
* Creates a new {@link JAXBContextFactory} instance. Pre-loads context cache with given classes
*
* @param classes
* @return ContextFactory with a pre-populated JAXBContext cache
* @throws jakarta.xml.bind.JAXBException if provided classes can't be used for JAXBContext
* generation most likely due to missing JAXB annotations
*/
public JAXBContextFactory build(List<Class<?>> classes) throws JAXBException {
JAXBContextFactory factory = new JAXBContextFactory(properties, jaxbContextInstantationMode);
factory.preloadContextCache(classes);
return factory;
}
}
}

52
jaxb-jakarta/src/main/java/feign/jaxb/JAXBContextInstantationMode.java

@ -0,0 +1,52 @@ @@ -0,0 +1,52 @@
/*
* Copyright 2012-2023 The Feign Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package feign.jaxb;
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
/**
* Provides differents ways to instantiate a JAXB Context.
*/
public enum JAXBContextInstantationMode {
CLASS {
@Override
JAXBContextCacheKey getJAXBContextCacheKey(Class<?> clazz) {
return new JAXBContextClassCacheKey(clazz);
}
@Override
JAXBContext getJAXBContext(Class<?> clazz) throws JAXBException {
return JAXBContext.newInstance(clazz);
}
},
PACKAGE {
@Override
JAXBContextCacheKey getJAXBContextCacheKey(Class<?> clazz) {
return new JAXBContextPackageCacheKey(clazz.getPackage().getName(), clazz.getClassLoader());
}
@Override
JAXBContext getJAXBContext(Class<?> clazz) throws JAXBException {
return JAXBContext.newInstance(clazz.getPackage().getName(), clazz.getClassLoader());
}
};
abstract JAXBContextCacheKey getJAXBContextCacheKey(Class<?> clazz);
abstract JAXBContext getJAXBContext(Class<?> clazz) throws JAXBException;
}

46
jaxb-jakarta/src/main/java/feign/jaxb/JAXBContextPackageCacheKey.java

@ -0,0 +1,46 @@ @@ -0,0 +1,46 @@
/*
* Copyright 2012-2023 The Feign Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package feign.jaxb;
import java.util.Objects;
/**
* Encapsulate data used to build the cache key of JAXBContext when created using package mode.
*/
final class JAXBContextPackageCacheKey implements JAXBContextCacheKey {
private final String packageName;
private final ClassLoader classLoader;
JAXBContextPackageCacheKey(String packageName, ClassLoader classLoader) {
this.packageName = packageName;
this.classLoader = classLoader;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
JAXBContextPackageCacheKey that = (JAXBContextPackageCacheKey) o;
return packageName.equals(that.packageName) && classLoader.equals(that.classLoader);
}
@Override
public int hashCode() {
return Objects.hash(packageName, classLoader);
}
}

127
jaxb-jakarta/src/main/java/feign/jaxb/JAXBDecoder.java

@ -0,0 +1,127 @@ @@ -0,0 +1,127 @@
/*
* Copyright 2012-2023 The Feign Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package feign.jaxb;
import feign.Response;
import feign.Util;
import feign.codec.DecodeException;
import feign.codec.Decoder;
import jakarta.xml.bind.JAXBException;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.sax.SAXSource;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* Decodes responses using JAXB with Jakarta Api. <br>
* <p>
* Basic example with with Feign.Builder:
* </p>
*
* <pre>
* JAXBContextFactory jaxbFactory = new JAXBContextFactory.Builder()
* .withMarshallerJAXBEncoding(&quot;UTF-8&quot;)
* .withMarshallerSchemaLocation(&quot;http://apihost http://apihost/schema.xsd&quot;)
* .build();
*
* api = Feign.builder()
* .decoder(new JAXBDecoder(jaxbFactory))
* .target(MyApi.class, &quot;http://api&quot;);
* </pre>
* <p>
* The JAXBContextFactory should be reused across requests as it caches the created JAXB contexts.
* </p>
*/
public class JAXBDecoder implements Decoder {
private final JAXBContextFactory jaxbContextFactory;
private final boolean namespaceAware;
public JAXBDecoder(JAXBContextFactory jaxbContextFactory) {
this.jaxbContextFactory = jaxbContextFactory;
this.namespaceAware = true;
}
private JAXBDecoder(Builder builder) {
this.jaxbContextFactory = builder.jaxbContextFactory;
this.namespaceAware = builder.namespaceAware;
}
@Override
public Object decode(Response response, Type type) throws IOException {
if (response.status() == 404 || response.status() == 204)
return Util.emptyValueOf(type);
if (response.body() == null)
return null;
while (type instanceof ParameterizedType) {
ParameterizedType ptype = (ParameterizedType) type;
type = ptype.getRawType();
}
if (!(type instanceof Class)) {
throw new UnsupportedOperationException(
"JAXB only supports decoding raw types. Found " + type);
}
try {
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
/* Explicitly control sax configuration to prevent XXE attacks */
saxParserFactory.setFeature("http://xml.org/sax/features/external-general-entities", false);
saxParserFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
saxParserFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false);
saxParserFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd",
false);
saxParserFactory.setNamespaceAware(namespaceAware);
return jaxbContextFactory.createUnmarshaller((Class<?>) type).unmarshal(new SAXSource(
saxParserFactory.newSAXParser().getXMLReader(),
new InputSource(response.body().asInputStream())));
} catch (JAXBException | ParserConfigurationException | SAXException e) {
throw new DecodeException(response.status(), e.toString(), response.request(), e);
} finally {
if (response.body() != null) {
response.body().close();
}
}
}
public static class Builder {
private boolean namespaceAware = true;
private JAXBContextFactory jaxbContextFactory;
/**
* Controls whether the underlying XML parser is namespace aware. Default is true.
*/
public Builder withNamespaceAware(boolean namespaceAware) {
this.namespaceAware = namespaceAware;
return this;
}
public Builder withJAXBContextFactory(JAXBContextFactory jaxbContextFactory) {
this.jaxbContextFactory = jaxbContextFactory;
return this;
}
public JAXBDecoder build() {
if (jaxbContextFactory == null) {
throw new IllegalStateException("JAXBContextFactory must be non-null");
}
return new JAXBDecoder(this);
}
}
}

67
jaxb-jakarta/src/main/java/feign/jaxb/JAXBEncoder.java

@ -0,0 +1,67 @@ @@ -0,0 +1,67 @@
/*
* Copyright 2012-2023 The Feign Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package feign.jaxb;
import feign.RequestTemplate;
import feign.codec.EncodeException;
import feign.codec.Encoder;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Marshaller;
import java.io.StringWriter;
import java.lang.reflect.Type;
/**
* Encodes requests using JAXB with Jakarta Api. <br>
* <p>
* Basic example with with Feign.Builder:
* </p>
*
* <pre>
* JAXBContextFactory jaxbFactory = new JAXBContextFactory.Builder()
* .withMarshallerJAXBEncoding("UTF-8")
* .withMarshallerSchemaLocation("http://apihost http://apihost/schema.xsd")
* .build();
*
* api = Feign.builder()
* .encoder(new JAXBEncoder(jaxbFactory))
* .target(MyApi.class, "http://api");
* </pre>
* <p>
* The JAXBContextFactory should be reused across requests as it caches the created JAXB contexts.
* </p>
*/
public class JAXBEncoder implements Encoder {
private final JAXBContextFactory jaxbContextFactory;
public JAXBEncoder(JAXBContextFactory jaxbContextFactory) {
this.jaxbContextFactory = jaxbContextFactory;
}
@Override
public void encode(Object object, Type bodyType, RequestTemplate template) {
if (!(bodyType instanceof Class)) {
throw new UnsupportedOperationException(
"JAXB only supports encoding raw types. Found " + bodyType);
}
try {
Marshaller marshaller = jaxbContextFactory.createMarshaller((Class<?>) bodyType);
StringWriter stringWriter = new StringWriter();
marshaller.marshal(object, stringWriter);
template.body(stringWriter.toString());
} catch (JAXBException e) {
throw new EncodeException(e.toString(), e);
}
}
}

280
jaxb-jakarta/src/test/java/feign/jaxb/JAXBCodecTest.java

@ -0,0 +1,280 @@ @@ -0,0 +1,280 @@
/*
* Copyright 2012-2023 The Feign Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package feign.jaxb;
import feign.Request;
import feign.Request.HttpMethod;
import feign.RequestTemplate;
import feign.Response;
import feign.Util;
import feign.codec.Encoder;
import jakarta.xml.bind.annotation.XmlAccessType;
import jakarta.xml.bind.annotation.XmlAccessorType;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlRootElement;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import static feign.Util.UTF_8;
import static feign.assertj.FeignAssertions.assertThat;
import static org.junit.Assert.assertEquals;
@SuppressWarnings("deprecation")
public class JAXBCodecTest {
@Rule
public final ExpectedException thrown = ExpectedException.none();
@Test
public void encodesXml() throws Exception {
MockObject mock = new MockObject();
mock.value = "Test";
RequestTemplate template = new RequestTemplate();
new JAXBEncoder(new JAXBContextFactory.Builder().build())
.encode(mock, MockObject.class, template);
assertThat(template)
.hasBody(
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><mockObject><value>Test</value></mockObject>");
}
@Test
public void doesntEncodeParameterizedTypes() throws Exception {
thrown.expect(UnsupportedOperationException.class);
thrown.expectMessage(
"JAXB only supports encoding raw types. Found java.util.Map<java.lang.String, ?>");
class ParameterizedHolder {
Map<String, ?> field;
}
Type parameterized = ParameterizedHolder.class.getDeclaredField("field").getGenericType();
RequestTemplate template = new RequestTemplate();
new JAXBEncoder(new JAXBContextFactory.Builder().build())
.encode(Collections.emptyMap(), parameterized, template);
}
@Test
public void encodesXmlWithCustomJAXBEncoding() throws Exception {
JAXBContextFactory jaxbContextFactory =
new JAXBContextFactory.Builder().withMarshallerJAXBEncoding("UTF-16").build();
Encoder encoder = new JAXBEncoder(jaxbContextFactory);
MockObject mock = new MockObject();
mock.value = "Test";
RequestTemplate template = new RequestTemplate();
encoder.encode(mock, MockObject.class, template);
assertThat(template).hasBody("<?xml version=\"1.0\" encoding=\"UTF-16\" "
+ "standalone=\"yes\"?><mockObject><value>Test</value></mockObject>");
}
@Test
public void encodesXmlWithCustomJAXBSchemaLocation() throws Exception {
JAXBContextFactory jaxbContextFactory =
new JAXBContextFactory.Builder()
.withMarshallerSchemaLocation("http://apihost http://apihost/schema.xsd")
.build();
Encoder encoder = new JAXBEncoder(jaxbContextFactory);
MockObject mock = new MockObject();
mock.value = "Test";
RequestTemplate template = new RequestTemplate();
encoder.encode(mock, MockObject.class, template);
assertThat(template).hasBody("<?xml version=\"1.0\" encoding=\"UTF-8\" " +
"standalone=\"yes\"?><mockObject xsi:schemaLocation=\"http://apihost " +
"http://apihost/schema.xsd\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" +
"<value>Test</value></mockObject>");
}
@Test
public void encodesXmlWithCustomJAXBNoNamespaceSchemaLocation() throws Exception {
JAXBContextFactory jaxbContextFactory =
new JAXBContextFactory.Builder()
.withMarshallerNoNamespaceSchemaLocation("http://apihost/schema.xsd").build();
Encoder encoder = new JAXBEncoder(jaxbContextFactory);
MockObject mock = new MockObject();
mock.value = "Test";
RequestTemplate template = new RequestTemplate();
encoder.encode(mock, MockObject.class, template);
assertThat(template)
.hasBody(
"<?xml version=\"1.0\" encoding=\"UTF-8\" "
+ "standalone=\"yes\"?><mockObject xsi:noNamespaceSchemaLocation=\"http://apihost/schema.xsd\" "
+ "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
+ "<value>Test</value></mockObject>");
}
@Test
public void encodesXmlWithCustomJAXBFormattedOutput() {
JAXBContextFactory jaxbContextFactory =
new JAXBContextFactory.Builder().withMarshallerFormattedOutput(true).build();
Encoder encoder = new JAXBEncoder(jaxbContextFactory);
MockObject mock = new MockObject();
mock.value = "Test";
RequestTemplate template = new RequestTemplate();
encoder.encode(mock, MockObject.class, template);
// RequestTemplate always expects a UNIX style newline.
assertThat(template).hasBody(
new StringBuilder().append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>")
.append("\n")
.append("<mockObject>")
.append("\n")
.append(" <value>Test</value>")
.append("\n")
.append("</mockObject>")
.append("\n")
.toString());
}
@Test
public void decodesXml() throws Exception {
MockObject mock = new MockObject();
mock.value = "Test";
String mockXml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><mockObject>"
+ "<value>Test</value></mockObject>";
Response response = Response.builder()
.status(200)
.reason("OK")
.request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8))
.headers(Collections.emptyMap())
.body(mockXml, UTF_8)
.build();
JAXBDecoder decoder = new JAXBDecoder(new JAXBContextFactory.Builder().build());
assertEquals(mock, decoder.decode(response, MockObject.class));
}
@Test
public void doesntDecodeParameterizedTypes() throws Exception {
thrown.expect(feign.codec.DecodeException.class);
thrown.expectMessage(
"java.util.Map is an interface, and JAXB can't handle interfaces.\n"
+ "\tthis problem is related to the following location:\n"
+ "\t\tat java.util.Map");
class ParameterizedHolder {
Map<String, ?> field;
}
Type parameterized = ParameterizedHolder.class.getDeclaredField("field").getGenericType();
Response response = Response.builder()
.status(200)
.reason("OK")
.request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8))
.headers(Collections.<String, Collection<String>>emptyMap())
.body("<foo/>", UTF_8)
.build();
new JAXBDecoder(new JAXBContextFactory.Builder().build()).decode(response, parameterized);
}
@XmlRootElement
static class Box<T> {
@XmlElement
private T t;
public void set(T t) {
this.t = t;
}
}
@Test
public void decodeAnnotatedParameterizedTypes() throws Exception {
JAXBContextFactory jaxbContextFactory =
new JAXBContextFactory.Builder().withMarshallerFormattedOutput(true).build();
Encoder encoder = new JAXBEncoder(jaxbContextFactory);
Box<String> boxStr = new Box<>();
boxStr.set("hello");
Box<Box<String>> boxBoxStr = new Box<>();
boxBoxStr.set(boxStr);
RequestTemplate template = new RequestTemplate();
encoder.encode(boxBoxStr, Box.class, template);
Response response = Response.builder()
.status(200)
.reason("OK")
.request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8))
.headers(Collections.<String, Collection<String>>emptyMap())
.body(template.body())
.build();
new JAXBDecoder(new JAXBContextFactory.Builder().build()).decode(response, Box.class);
}
/**
* Enabled via {@link feign.Feign.Builder#dismiss404()}
*/
@Test
public void notFoundDecodesToEmpty() throws Exception {
Response response = Response.builder()
.status(404)
.reason("NOT FOUND")
.request(Request.create(HttpMethod.GET, "/api", Collections.emptyMap(), null, Util.UTF_8))
.headers(Collections.<String, Collection<String>>emptyMap())
.build();
assertThat((byte[]) new JAXBDecoder(new JAXBContextFactory.Builder().build())
.decode(response, byte[].class)).isEmpty();
}
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
static class MockObject {
@XmlElement
private String value;
@Override
public boolean equals(Object obj) {
if (obj instanceof MockObject) {
MockObject other = (MockObject) obj;
return value.equals(other.value);
}
return false;
}
@Override
public int hashCode() {
return value != null ? value.hashCode() : 0;
}
}
}

151
jaxb-jakarta/src/test/java/feign/jaxb/JAXBContextFactoryTest.java

@ -0,0 +1,151 @@ @@ -0,0 +1,151 @@
/*
* Copyright 2012-2023 The Feign Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package feign.jaxb;
import feign.jaxb.mock.onepackage.AnotherMockedJAXBObject;
import feign.jaxb.mock.onepackage.MockedJAXBObject;
import jakarta.xml.bind.Marshaller;
import org.junit.Test;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.*;
public class JAXBContextFactoryTest {
@Test
public void buildsMarshallerWithJAXBEncodingProperty() throws Exception {
JAXBContextFactory factory =
new JAXBContextFactory.Builder().withMarshallerJAXBEncoding("UTF-16").build();
Marshaller marshaller = factory.createMarshaller(Object.class);
assertEquals("UTF-16", marshaller.getProperty(Marshaller.JAXB_ENCODING));
}
@Test
public void buildsMarshallerWithSchemaLocationProperty() throws Exception {
JAXBContextFactory factory =
new JAXBContextFactory.Builder()
.withMarshallerSchemaLocation("http://apihost http://apihost/schema.xsd")
.build();
Marshaller marshaller = factory.createMarshaller(Object.class);
assertEquals("http://apihost http://apihost/schema.xsd",
marshaller.getProperty(Marshaller.JAXB_SCHEMA_LOCATION));
}
@Test
public void buildsMarshallerWithNoNamespaceSchemaLocationProperty() throws Exception {
JAXBContextFactory factory =
new JAXBContextFactory.Builder()
.withMarshallerNoNamespaceSchemaLocation("http://apihost/schema.xsd").build();
Marshaller marshaller = factory.createMarshaller(Object.class);
assertEquals("http://apihost/schema.xsd",
marshaller.getProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION));
}
@Test
public void buildsMarshallerWithFormattedOutputProperty() throws Exception {
JAXBContextFactory factory =
new JAXBContextFactory.Builder().withMarshallerFormattedOutput(true).build();
Marshaller marshaller = factory.createMarshaller(Object.class);
assertTrue((Boolean) marshaller.getProperty(Marshaller.JAXB_FORMATTED_OUTPUT));
}
@Test
public void buildsMarshallerWithFragmentProperty() throws Exception {
JAXBContextFactory factory =
new JAXBContextFactory.Builder().withMarshallerFragment(true).build();
Marshaller marshaller = factory.createMarshaller(Object.class);
assertTrue((Boolean) marshaller.getProperty(Marshaller.JAXB_FRAGMENT));
}
@Test
public void testPreloadCache() throws Exception {
List<Class<?>> classes = Arrays.asList(String.class, Integer.class);
JAXBContextFactory factory =
new JAXBContextFactory.Builder().build(classes);
Field f = factory.getClass().getDeclaredField("jaxbContexts"); // NoSuchFieldException
f.setAccessible(true);
Map internalCache = (Map) f.get(factory); // IllegalAccessException
assertFalse(internalCache.isEmpty());
assertTrue(internalCache.size() == classes.size());
assertNotNull(internalCache.get(new JAXBContextClassCacheKey(String.class)));
assertNotNull(internalCache.get(new JAXBContextClassCacheKey(Integer.class)));
}
@Test
public void testClassModeInstantiation() throws Exception {
List<Class<?>> classes = Arrays.asList(String.class, Integer.class);
JAXBContextFactory factory =
new JAXBContextFactory.Builder()
.withJAXBContextInstantiationMode(JAXBContextInstantationMode.CLASS)
.build(classes);
Field f = factory.getClass().getDeclaredField("jaxbContexts"); // NoSuchFieldException
f.setAccessible(true);
Map internalCache = (Map) f.get(factory); // IllegalAccessException
assertFalse(internalCache.isEmpty());
assertEquals(internalCache.size(), classes.size());
assertNotNull(internalCache.get(new JAXBContextClassCacheKey(String.class)));
assertNotNull(internalCache.get(new JAXBContextClassCacheKey(Integer.class)));
}
@Test
public void testPackageModeInstantiationUsingSamePackage() throws Exception {
JAXBContextFactory factory = new JAXBContextFactory.Builder()
.withJAXBContextInstantiationMode(JAXBContextInstantationMode.PACKAGE)
.build(Arrays.asList(MockedJAXBObject.class, AnotherMockedJAXBObject.class));
Field f = factory.getClass().getDeclaredField("jaxbContexts"); // NoSuchFieldException
f.setAccessible(true);
Map internalCache = (Map) f.get(factory); // IllegalAccessException
assertFalse(internalCache.isEmpty());
assertEquals(1, internalCache.size());
assertNotNull(internalCache.get(new JAXBContextPackageCacheKey("feign.jaxb.mock.onepackage",
AnotherMockedJAXBObject.class.getClassLoader())));
}
@Test
public void testPackageModeInstantiationUsingMultiplePackages() throws Exception {
JAXBContextFactory factory = new JAXBContextFactory.Builder()
.withJAXBContextInstantiationMode(JAXBContextInstantationMode.PACKAGE)
.build(Arrays.asList(MockedJAXBObject.class,
feign.jaxb.mock.anotherpackage.MockedJAXBObject.class));
Field f = factory.getClass().getDeclaredField("jaxbContexts"); // NoSuchFieldException
f.setAccessible(true);
Map internalCache = (Map) f.get(factory); // IllegalAccessException
assertFalse(internalCache.isEmpty());
assertEquals(2, internalCache.size());
assertNotNull(internalCache.get(new JAXBContextPackageCacheKey("feign.jaxb.mock.onepackage",
MockedJAXBObject.class.getClassLoader())));
assertNotNull(internalCache.get(new JAXBContextPackageCacheKey("feign.jaxb.mock.anotherpackage",
feign.jaxb.mock.anotherpackage.MockedJAXBObject.class.getClassLoader())));
}
}

161
jaxb-jakarta/src/test/java/feign/jaxb/examples/AWSSignatureVersion4.java

@ -0,0 +1,161 @@ @@ -0,0 +1,161 @@
/*
* Copyright 2012-2023 The Feign Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package feign.jaxb.examples;
import feign.Request;
import feign.RequestTemplate;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import static feign.Util.UTF_8;
// http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html
public class AWSSignatureVersion4 {
private static final String EMPTY_STRING_HASH =
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
private static final SimpleDateFormat iso8601 = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
static {
iso8601.setTimeZone(TimeZone.getTimeZone("GMT"));
}
String region = "us-east-1";
String service = "iam";
String accessKey;
String secretKey;
public AWSSignatureVersion4(String accessKey, String secretKey) {
this.accessKey = accessKey;
this.secretKey = secretKey;
}
static byte[] hmacSHA256(String data, byte[] key) {
try {
String algorithm = "HmacSHA256";
Mac mac = Mac.getInstance(algorithm);
mac.init(new SecretKeySpec(key, algorithm));
return mac.doFinal(data.getBytes(UTF_8));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static String canonicalString(RequestTemplate input, String host) {
StringBuilder canonicalRequest = new StringBuilder();
// HTTPRequestMethod + '\n' +
canonicalRequest.append(input.method()).append('\n');
// CanonicalURI + '\n' +
canonicalRequest.append(URI.create(input.url()).getPath()).append('\n');
// CanonicalQueryString + '\n' +
canonicalRequest.append(input.queryLine().substring(1));
canonicalRequest.append('\n');
// CanonicalHeaders + '\n' +
canonicalRequest.append("host:").append(host).append('\n');
canonicalRequest.append('\n');
// SignedHeaders + '\n' +
canonicalRequest.append("host").append('\n');
// HexEncode(Hash(Payload))
byte[] data = input.body();
String bodyText = (data != null) ? new String(data, input.requestCharset()) : null;
if (bodyText != null) {
canonicalRequest.append(hex(sha256(bodyText)));
} else {
canonicalRequest.append(EMPTY_STRING_HASH);
}
return canonicalRequest.toString();
}
private static String toSign(String timestamp, String credentialScope, String canonicalRequest) {
StringBuilder toSign = new StringBuilder();
// Algorithm + '\n' +
toSign.append("AWS4-HMAC-SHA256").append('\n');
// RequestDate + '\n' +
toSign.append(timestamp).append('\n');
// CredentialScope + '\n' +
toSign.append(credentialScope).append('\n');
// HexEncode(Hash(CanonicalRequest))
toSign.append(hex(sha256(canonicalRequest)));
return toSign.toString();
}
private static String hex(byte[] data) {
StringBuilder result = new StringBuilder(data.length * 2);
for (byte b : data) {
result.append(String.format("%02x", b & 0xff));
}
return result.toString();
}
static byte[] sha256(String data) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
return digest.digest(data.getBytes(UTF_8));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public Request apply(RequestTemplate input) {
if (!input.headers().isEmpty()) {
throw new UnsupportedOperationException("headers not supported");
}
if (input.body() != null) {
throw new UnsupportedOperationException("body not supported");
}
String host = URI.create(input.url()).getHost();
String timestamp;
synchronized (iso8601) {
timestamp = iso8601.format(new Date());
}
String credentialScope =
String.format("%s/%s/%s/%s", timestamp.substring(0, 8), region, service, "aws4_request");
input.query("X-Amz-Algorithm", "AWS4-HMAC-SHA256");
input.query("X-Amz-Credential", accessKey + "/" + credentialScope);
input.query("X-Amz-Date", timestamp);
input.query("X-Amz-SignedHeaders", "host");
input.header("Host", host);
String canonicalString = canonicalString(input, host);
String toSign = toSign(timestamp, credentialScope, canonicalString);
byte[] signatureKey = signatureKey(secretKey, timestamp);
String signature = hex(hmacSHA256(toSign, signatureKey));
input.query("X-Amz-Signature", signature);
return input.request();
}
byte[] signatureKey(String secretKey, String timestamp) {
byte[] kSecret = ("AWS4" + secretKey).getBytes(UTF_8);
byte[] kDate = hmacSHA256(timestamp.substring(0, 8), kSecret);
byte[] kRegion = hmacSHA256(region, kDate);
byte[] kService = hmacSHA256(service, kRegion);
byte[] kSigning = hmacSHA256("aws4_request", kService);
return kSigning;
}
}

90
jaxb-jakarta/src/test/java/feign/jaxb/examples/IAMExample.java

@ -0,0 +1,90 @@ @@ -0,0 +1,90 @@
/*
* Copyright 2012-2023 The Feign Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package feign.jaxb.examples;
import feign.*;
import feign.jaxb.JAXBContextFactory;
import feign.jaxb.JAXBDecoder;
import jakarta.xml.bind.annotation.*;
public class IAMExample {
public static void main(String... args) {
IAM iam = Feign.builder()
.decoder(new JAXBDecoder(new JAXBContextFactory.Builder().build()))
.target(new IAMTarget(args[0], args[1]));
GetUserResponse response = iam.userResponse();
System.out.println("UserId: " + response.result.user.id);
}
interface IAM {
@RequestLine("GET /?Action=GetUser&Version=2010-05-08")
GetUserResponse userResponse();
}
static class IAMTarget extends AWSSignatureVersion4 implements Target<IAM> {
private IAMTarget(String accessKey, String secretKey) {
super(accessKey, secretKey);
}
@Override
public Class<IAM> type() {
return IAM.class;
}
@Override
public String name() {
return "iam";
}
@Override
public String url() {
return "https://iam.amazonaws.com";
}
@Override
public Request apply(RequestTemplate in) {
in.target(url());
return super.apply(in);
}
}
@XmlRootElement(name = "GetUserResponse", namespace = "https://iam.amazonaws.com/doc/2010-05-08/")
@XmlAccessorType(XmlAccessType.FIELD)
static class GetUserResponse {
@XmlElement(name = "GetUserResult")
private GetUserResult result;
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "GetUserResult")
static class GetUserResult {
@XmlElement(name = "User")
private User user;
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "User")
static class User {
@XmlElement(name = "UserId")
private String id;
}
}

16
jaxb-jakarta/src/test/java/feign/jaxb/examples/package-info.java

@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
/*
* Copyright 2012-2023 The Feign Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
@jakarta.xml.bind.annotation.XmlSchema(namespace = "https://iam.amazonaws.com/doc/2010-05-08/",
elementFormDefault = jakarta.xml.bind.annotation.XmlNsForm.QUALIFIED)
package feign.jaxb.examples;

21
jaxb-jakarta/src/test/java/feign/jaxb/mock/anotherpackage/MockedJAXBObject.java

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
/*
* Copyright 2012-2023 The Feign Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package feign.jaxb.mock.anotherpackage;
import jakarta.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "anothertest")
public class MockedJAXBObject {
}

25
jaxb-jakarta/src/test/java/feign/jaxb/mock/anotherpackage/ObjectFactory.java

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
/*
* Copyright 2012-2023 The Feign Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package feign.jaxb.mock.anotherpackage;
import jakarta.xml.bind.annotation.XmlRegistry;
@XmlRegistry
public class ObjectFactory {
public MockedJAXBObject createMockedJAXBObject() {
return new MockedJAXBObject();
}
}

21
jaxb-jakarta/src/test/java/feign/jaxb/mock/onepackage/AnotherMockedJAXBObject.java

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
/*
* Copyright 2012-2023 The Feign Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package feign.jaxb.mock.onepackage;
import jakarta.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class AnotherMockedJAXBObject {
}

21
jaxb-jakarta/src/test/java/feign/jaxb/mock/onepackage/MockedJAXBObject.java

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
/*
* Copyright 2012-2023 The Feign Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package feign.jaxb.mock.onepackage;
import jakarta.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "test")
public class MockedJAXBObject {
}

29
jaxb-jakarta/src/test/java/feign/jaxb/mock/onepackage/ObjectFactory.java

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
/*
* Copyright 2012-2023 The Feign Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package feign.jaxb.mock.onepackage;
import jakarta.xml.bind.annotation.XmlRegistry;
@XmlRegistry
public class ObjectFactory {
public MockedJAXBObject createMockedJAXBObject() {
return new MockedJAXBObject();
}
public AnotherMockedJAXBObject createAnotherMockedJAXBObject() {
return new AnotherMockedJAXBObject();
}
}
Loading…
Cancel
Save