Skip to content

Commit 9b01564

Browse files
authored
added jaxb-jakarta module on the basis of jaxb module (#2014)
1 parent 29c25f6 commit 9b01564

18 files changed

+1409
-0
lines changed

jaxb-jakarta/pom.xml

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
4+
Copyright 2012-2023 The Feign Authors
5+
6+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
7+
in compliance with the License. You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software distributed under the License
12+
is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
13+
or implied. See the License for the specific language governing permissions and limitations under
14+
the License.
15+
16+
-->
17+
<project xmlns="http://maven.apache.org/POM/4.0.0"
18+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
19+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
20+
<modelVersion>4.0.0</modelVersion>
21+
22+
<parent>
23+
<groupId>io.github.openfeign</groupId>
24+
<artifactId>parent</artifactId>
25+
<version>12.4-SNAPSHOT</version>
26+
</parent>
27+
28+
<artifactId>feign-jaxb-jakarta</artifactId>
29+
<name>Feign JAXB Jakarta</name>
30+
<description>Feign JAXB Jakarta</description>
31+
32+
<properties>
33+
<main.basedir>${project.basedir}/..</main.basedir>
34+
</properties>
35+
36+
<dependencies>
37+
<dependency>
38+
<groupId>${project.groupId}</groupId>
39+
<artifactId>feign-core</artifactId>
40+
</dependency>
41+
42+
<dependency>
43+
<groupId>${project.groupId}</groupId>
44+
<artifactId>feign-core</artifactId>
45+
<type>test-jar</type>
46+
<scope>test</scope>
47+
</dependency>
48+
<dependency>
49+
<groupId>jakarta.xml.bind</groupId>
50+
<artifactId>jakarta.xml.bind-api</artifactId>
51+
<version>4.0.0</version>
52+
</dependency>
53+
54+
<!-- Test -->
55+
<dependency>
56+
<groupId>com.sun.xml.bind</groupId>
57+
<artifactId>jaxb-impl</artifactId>
58+
<version>4.0.0</version>
59+
<scope>test</scope>
60+
</dependency>
61+
</dependencies>
62+
63+
</project>
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* Copyright 2012-2023 The Feign Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5+
* in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License
10+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11+
* or implied. See the License for the specific language governing permissions and limitations under
12+
* the License.
13+
*/
14+
package feign.jaxb;
15+
16+
/** Encapsulate data used to build the cache key of JAXBContext. */
17+
interface JAXBContextCacheKey {}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2012-2023 The Feign Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5+
* in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License
10+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11+
* or implied. See the License for the specific language governing permissions and limitations under
12+
* the License.
13+
*/
14+
package feign.jaxb;
15+
16+
import java.util.Objects;
17+
18+
/** Encapsulate data used to build the cache key of JAXBContext when created using class mode. */
19+
final class JAXBContextClassCacheKey implements JAXBContextCacheKey {
20+
21+
private final Class<?> clazz;
22+
23+
JAXBContextClassCacheKey(Class<?> clazz) {
24+
this.clazz = clazz;
25+
}
26+
27+
@Override
28+
public boolean equals(Object o) {
29+
if (this == o) return true;
30+
if (o == null || getClass() != o.getClass()) return false;
31+
JAXBContextClassCacheKey that = (JAXBContextClassCacheKey) o;
32+
return clazz.equals(that.clazz);
33+
}
34+
35+
@Override
36+
public int hashCode() {
37+
return Objects.hash(clazz);
38+
}
39+
}
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/*
2+
* Copyright 2012-2023 The Feign Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5+
* in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License
10+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11+
* or implied. See the License for the specific language governing permissions and limitations under
12+
* the License.
13+
*/
14+
package feign.jaxb;
15+
16+
import jakarta.xml.bind.*;
17+
import java.util.HashMap;
18+
import java.util.List;
19+
import java.util.Map;
20+
import java.util.Map.Entry;
21+
import java.util.concurrent.ConcurrentHashMap;
22+
23+
/**
24+
* Creates and caches JAXB contexts as well as creates Marshallers and Unmarshallers for each
25+
* context. Since JAXB contexts creation can be an expensive task, JAXB context can be preloaded on
26+
* factory creation otherwise they will be created and cached dynamically when needed.
27+
*/
28+
public final class JAXBContextFactory {
29+
30+
private final ConcurrentHashMap<JAXBContextCacheKey, JAXBContext> jaxbContexts =
31+
new ConcurrentHashMap<>(64);
32+
private final Map<String, Object> properties;
33+
private final JAXBContextInstantationMode jaxbContextInstantationMode;
34+
35+
private JAXBContextFactory(
36+
Map<String, Object> properties, JAXBContextInstantationMode jaxbContextInstantationMode) {
37+
this.properties = properties;
38+
this.jaxbContextInstantationMode = jaxbContextInstantationMode;
39+
}
40+
41+
/** Creates a new {@link jakarta.xml.bind.Unmarshaller} that handles the supplied class. */
42+
public Unmarshaller createUnmarshaller(Class<?> clazz) throws JAXBException {
43+
return getContext(clazz).createUnmarshaller();
44+
}
45+
46+
/** Creates a new {@link jakarta.xml.bind.Marshaller} that handles the supplied class. */
47+
public Marshaller createMarshaller(Class<?> clazz) throws JAXBException {
48+
Marshaller marshaller = getContext(clazz).createMarshaller();
49+
setMarshallerProperties(marshaller);
50+
return marshaller;
51+
}
52+
53+
private void setMarshallerProperties(Marshaller marshaller) throws PropertyException {
54+
for (Entry<String, Object> en : properties.entrySet()) {
55+
marshaller.setProperty(en.getKey(), en.getValue());
56+
}
57+
}
58+
59+
private JAXBContext getContext(Class<?> clazz) throws JAXBException {
60+
JAXBContextCacheKey cacheKey = jaxbContextInstantationMode.getJAXBContextCacheKey(clazz);
61+
JAXBContext jaxbContext = this.jaxbContexts.get(cacheKey);
62+
63+
if (jaxbContext == null) {
64+
jaxbContext = jaxbContextInstantationMode.getJAXBContext(clazz);
65+
this.jaxbContexts.putIfAbsent(cacheKey, jaxbContext);
66+
}
67+
return jaxbContext;
68+
}
69+
70+
/**
71+
* Will preload factory's cache with JAXBContext for provided classes
72+
*
73+
* @param classes
74+
* @throws jakarta.xml.bind.JAXBException
75+
*/
76+
private void preloadContextCache(List<Class<?>> classes) throws JAXBException {
77+
if (classes != null && !classes.isEmpty()) {
78+
for (Class<?> clazz : classes) {
79+
getContext(clazz);
80+
}
81+
}
82+
}
83+
84+
/** Creates instances of {@link JAXBContextFactory}. */
85+
public static class Builder {
86+
87+
private final Map<String, Object> properties = new HashMap<>(10);
88+
89+
private JAXBContextInstantationMode jaxbContextInstantationMode =
90+
JAXBContextInstantationMode.CLASS;
91+
92+
/** Sets the jaxb.encoding property of any Marshaller created by this factory. */
93+
public Builder withMarshallerJAXBEncoding(String value) {
94+
properties.put(Marshaller.JAXB_ENCODING, value);
95+
return this;
96+
}
97+
98+
/** Sets the jaxb.schemaLocation property of any Marshaller created by this factory. */
99+
public Builder withMarshallerSchemaLocation(String value) {
100+
properties.put(Marshaller.JAXB_SCHEMA_LOCATION, value);
101+
return this;
102+
}
103+
104+
/**
105+
* Sets the jaxb.noNamespaceSchemaLocation property of any Marshaller created by this factory.
106+
*/
107+
public Builder withMarshallerNoNamespaceSchemaLocation(String value) {
108+
properties.put(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, value);
109+
return this;
110+
}
111+
112+
/** Sets the jaxb.formatted.output property of any Marshaller created by this factory. */
113+
public Builder withMarshallerFormattedOutput(Boolean value) {
114+
properties.put(Marshaller.JAXB_FORMATTED_OUTPUT, value);
115+
return this;
116+
}
117+
118+
/** Sets the jaxb.fragment property of any Marshaller created by this factory. */
119+
public Builder withMarshallerFragment(Boolean value) {
120+
properties.put(Marshaller.JAXB_FRAGMENT, value);
121+
return this;
122+
}
123+
124+
/**
125+
* Sets the given property of any Marshaller created by this factory.
126+
*
127+
* <p>Example : <br>
128+
* <br>
129+
* <code>
130+
* new JAXBContextFactory.Builder()
131+
* .withProperty("com.sun.xml.internal.bind.xmlHeaders", "&lt;!DOCTYPE Example SYSTEM \&quot;example.dtd\&quot;&gt;")
132+
* .build();
133+
* </code>
134+
*/
135+
public Builder withProperty(String key, Object value) {
136+
properties.put(key, value);
137+
return this;
138+
}
139+
140+
/**
141+
* Provide an instantiation mode for JAXB Contexts, can be class or package, default is class if
142+
* this method is not called.
143+
*
144+
* <p>Example : <br>
145+
* <br>
146+
* <code>
147+
* new JAXBContextFactory.Builder()
148+
* .withJAXBContextInstantiationMode(JAXBContextInstantationMode.PACKAGE)
149+
* .build();
150+
* </code>
151+
*/
152+
public Builder withJAXBContextInstantiationMode(
153+
JAXBContextInstantationMode jaxbContextInstantiationMode) {
154+
this.jaxbContextInstantationMode = jaxbContextInstantiationMode;
155+
return this;
156+
}
157+
158+
/** Creates a new {@link JAXBContextFactory} instance with a lazy loading cached context */
159+
public JAXBContextFactory build() {
160+
return new JAXBContextFactory(properties, jaxbContextInstantationMode);
161+
}
162+
163+
/**
164+
* Creates a new {@link JAXBContextFactory} instance. Pre-loads context cache with given classes
165+
*
166+
* @param classes
167+
* @return ContextFactory with a pre-populated JAXBContext cache
168+
* @throws jakarta.xml.bind.JAXBException if provided classes can't be used for JAXBContext
169+
* generation most likely due to missing JAXB annotations
170+
*/
171+
public JAXBContextFactory build(List<Class<?>> classes) throws JAXBException {
172+
JAXBContextFactory factory = new JAXBContextFactory(properties, jaxbContextInstantationMode);
173+
factory.preloadContextCache(classes);
174+
return factory;
175+
}
176+
}
177+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2012-2023 The Feign Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5+
* in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License
10+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11+
* or implied. See the License for the specific language governing permissions and limitations under
12+
* the License.
13+
*/
14+
package feign.jaxb;
15+
16+
import jakarta.xml.bind.JAXBContext;
17+
import jakarta.xml.bind.JAXBException;
18+
19+
/** Provides differents ways to instantiate a JAXB Context. */
20+
public enum JAXBContextInstantationMode {
21+
CLASS {
22+
@Override
23+
JAXBContextCacheKey getJAXBContextCacheKey(Class<?> clazz) {
24+
return new JAXBContextClassCacheKey(clazz);
25+
}
26+
27+
@Override
28+
JAXBContext getJAXBContext(Class<?> clazz) throws JAXBException {
29+
return JAXBContext.newInstance(clazz);
30+
}
31+
},
32+
33+
PACKAGE {
34+
@Override
35+
JAXBContextCacheKey getJAXBContextCacheKey(Class<?> clazz) {
36+
return new JAXBContextPackageCacheKey(clazz.getPackage().getName(), clazz.getClassLoader());
37+
}
38+
39+
@Override
40+
JAXBContext getJAXBContext(Class<?> clazz) throws JAXBException {
41+
return JAXBContext.newInstance(clazz.getPackage().getName(), clazz.getClassLoader());
42+
}
43+
};
44+
45+
abstract JAXBContextCacheKey getJAXBContextCacheKey(Class<?> clazz);
46+
47+
abstract JAXBContext getJAXBContext(Class<?> clazz) throws JAXBException;
48+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2012-2023 The Feign Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5+
* in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License
10+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11+
* or implied. See the License for the specific language governing permissions and limitations under
12+
* the License.
13+
*/
14+
package feign.jaxb;
15+
16+
import java.util.Objects;
17+
18+
/** Encapsulate data used to build the cache key of JAXBContext when created using package mode. */
19+
final class JAXBContextPackageCacheKey implements JAXBContextCacheKey {
20+
21+
private final String packageName;
22+
23+
private final ClassLoader classLoader;
24+
25+
JAXBContextPackageCacheKey(String packageName, ClassLoader classLoader) {
26+
this.packageName = packageName;
27+
this.classLoader = classLoader;
28+
}
29+
30+
@Override
31+
public boolean equals(Object o) {
32+
if (this == o) return true;
33+
if (o == null || getClass() != o.getClass()) return false;
34+
JAXBContextPackageCacheKey that = (JAXBContextPackageCacheKey) o;
35+
return packageName.equals(that.packageName) && classLoader.equals(that.classLoader);
36+
}
37+
38+
@Override
39+
public int hashCode() {
40+
return Objects.hash(packageName, classLoader);
41+
}
42+
}

0 commit comments

Comments
 (0)