Browse Source

feat(jaxb-package): possibility to choose a JAXBContext instantiation using package mode (#2005)

Co-authored-by: jernat <jernat.morbal@gmail.com>
Co-authored-by: Marvin Froeder <velo@users.noreply.github.com>
pull/2010/head
Jeremy Balan 2 years ago committed by GitHub
parent
commit
7557597a4c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 20
      jaxb/src/main/java/feign/jaxb/JAXBContextCacheKey.java
  2. 43
      jaxb/src/main/java/feign/jaxb/JAXBContextClassCacheKey.java
  3. 41
      jaxb/src/main/java/feign/jaxb/JAXBContextFactory.java
  4. 51
      jaxb/src/main/java/feign/jaxb/JAXBContextInstantationMode.java
  5. 46
      jaxb/src/main/java/feign/jaxb/JAXBContextPackageCacheKey.java
  6. 71
      jaxb/src/test/java/feign/jaxb/JAXBContextFactoryTest.java
  7. 20
      jaxb/src/test/java/feign/jaxb/mock/anotherpackage/MockedJAXBObject.java
  8. 24
      jaxb/src/test/java/feign/jaxb/mock/anotherpackage/ObjectFactory.java
  9. 20
      jaxb/src/test/java/feign/jaxb/mock/onepackage/AnotherMockedJAXBObject.java
  10. 20
      jaxb/src/test/java/feign/jaxb/mock/onepackage/MockedJAXBObject.java
  11. 28
      jaxb/src/test/java/feign/jaxb/mock/onepackage/ObjectFactory.java

20
jaxb/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/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);
}
}

41
jaxb/src/main/java/feign/jaxb/JAXBContextFactory.java

@ -31,12 +31,15 @@ import javax.xml.bind.Unmarshaller; @@ -31,12 +31,15 @@ import javax.xml.bind.Unmarshaller;
*/
public final class JAXBContextFactory {
private final ConcurrentHashMap<Class<?>, JAXBContext> jaxbContexts =
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) {
private JAXBContextFactory(Map<String, Object> properties,
JAXBContextInstantationMode jaxbContextInstantationMode) {
this.properties = properties;
this.jaxbContextInstantationMode = jaxbContextInstantationMode;
}
/**
@ -62,10 +65,12 @@ public final class JAXBContextFactory { @@ -62,10 +65,12 @@ public final class JAXBContextFactory {
}
private JAXBContext getContext(Class<?> clazz) throws JAXBException {
JAXBContext jaxbContext = this.jaxbContexts.get(clazz);
JAXBContextCacheKey cacheKey = jaxbContextInstantationMode.getJAXBContextCacheKey(clazz);
JAXBContext jaxbContext = this.jaxbContexts.get(cacheKey);
if (jaxbContext == null) {
jaxbContext = JAXBContext.newInstance(clazz);
this.jaxbContexts.putIfAbsent(clazz, jaxbContext);
jaxbContext = jaxbContextInstantationMode.getJAXBContext(clazz);
this.jaxbContexts.putIfAbsent(cacheKey, jaxbContext);
}
return jaxbContext;
}
@ -91,6 +96,9 @@ public final class JAXBContextFactory { @@ -91,6 +96,9 @@ public final class JAXBContextFactory {
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.
*/
@ -149,12 +157,31 @@ public final class JAXBContextFactory { @@ -149,12 +157,31 @@ public final class JAXBContextFactory {
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 feign.jaxb.JAXBContextFactory} instance with a lazy loading cached
* context
*/
public JAXBContextFactory build() {
return new JAXBContextFactory(properties);
return new JAXBContextFactory(properties, jaxbContextInstantationMode);
}
/**
@ -167,7 +194,7 @@ public final class JAXBContextFactory { @@ -167,7 +194,7 @@ public final class JAXBContextFactory {
* likely due to missing JAXB annotations
*/
public JAXBContextFactory build(List<Class<?>> classes) throws JAXBException {
JAXBContextFactory factory = new JAXBContextFactory(properties);
JAXBContextFactory factory = new JAXBContextFactory(properties, jaxbContextInstantationMode);
factory.preloadContextCache(classes);
return factory;
}

51
jaxb/src/main/java/feign/jaxb/JAXBContextInstantationMode.java

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
/*
* 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 javax.xml.bind.JAXBContext;
import javax.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/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);
}
}

71
jaxb/src/test/java/feign/jaxb/JAXBContextFactoryTest.java

@ -13,16 +13,15 @@ @@ -13,16 +13,15 @@
*/
package feign.jaxb;
import feign.jaxb.mock.onepackage.AnotherMockedJAXBObject;
import feign.jaxb.mock.onepackage.MockedJAXBObject;
import org.junit.Test;
import javax.xml.bind.Marshaller;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import javax.xml.bind.Marshaller;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
public class JAXBContextFactoryTest {
@ -88,9 +87,65 @@ public class JAXBContextFactoryTest { @@ -88,9 +87,65 @@ public class JAXBContextFactoryTest {
Map internalCache = (Map) f.get(factory); // IllegalAccessException
assertFalse(internalCache.isEmpty());
assertTrue(internalCache.size() == classes.size());
assertNotNull(internalCache.get(String.class));
assertNotNull(internalCache.get(Integer.class));
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())));
}
}

20
jaxb/src/test/java/feign/jaxb/mock/anotherpackage/MockedJAXBObject.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.mock.anotherpackage;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "anothertest")
public class MockedJAXBObject {
}

24
jaxb/src/test/java/feign/jaxb/mock/anotherpackage/ObjectFactory.java

@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
/*
* 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 javax.xml.bind.annotation.XmlRegistry;
@XmlRegistry
public class ObjectFactory {
public MockedJAXBObject createMockedJAXBObject() {
return new MockedJAXBObject();
}
}

20
jaxb/src/test/java/feign/jaxb/mock/onepackage/AnotherMockedJAXBObject.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.mock.onepackage;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class AnotherMockedJAXBObject {
}

20
jaxb/src/test/java/feign/jaxb/mock/onepackage/MockedJAXBObject.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.mock.onepackage;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "test")
public class MockedJAXBObject {
}

28
jaxb/src/test/java/feign/jaxb/mock/onepackage/ObjectFactory.java

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
/*
* 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 javax.xml.bind.annotation.XmlRegistry;
@XmlRegistry
public class ObjectFactory {
public MockedJAXBObject createMockedJAXBObject() {
return new MockedJAXBObject();
}
public AnotherMockedJAXBObject createAnotherMockedJAXBObject() {
return new AnotherMockedJAXBObject();
}
}
Loading…
Cancel
Save