Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 1 commit into from
Apr 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
63 changes: 63 additions & 0 deletions jaxb-jakarta/pom.xml
Original file line number Diff line number Diff line change
@@ -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 changes: 20 additions & 0 deletions jaxb-jakarta/src/main/java/feign/jaxb/JAXBContextCacheKey.java
Original file line number Diff line number Diff line change
@@ -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 {
}
Original file line number Diff line number Diff line change
@@ -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 changes: 196 additions & 0 deletions jaxb-jakarta/src/main/java/feign/jaxb/JAXBContextFactory.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
Original file line number Diff line number Diff line change
@@ -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;
}