-
Notifications
You must be signed in to change notification settings - Fork 79
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Copy guice (javax.inject) module over to a new guice 7 (jakarta.inject) module. Replace javax imports with jakarta imports, and leave everything else the same. Fixes #206
- Loading branch information
1 parent
9a3fcd1
commit ec86650
Showing
15 changed files
with
983 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
# jackson-module-guice7 | ||
|
||
## Documentation | ||
|
||
This is a copy of jackson-module-guice that works with guice version 7, using the jakarta.inject namespace. | ||
|
||
This extension allows Jackson to delegate ObjectMapper creation and value injection to Guice when handling data bindings. | ||
Using the ObjectMapperModule you can register Jackson data binding modules like so: | ||
|
||
~~~~~ | ||
Injector injector = Guice.createInjector( | ||
new ObjectMapperModule().registerModule(new IntegerAsBase16Module()) | ||
); | ||
public class IntegerAsBase16Module extends SimpleModule | ||
{ | ||
public IntegerAsBase16Module() { | ||
super("IntegerAsBase16"); | ||
addSerializer( Integer.class, | ||
new JsonSerializer<Integer>() { | ||
@Override | ||
public void serialize( Integer integer, JsonGenerator jsonGenerator, SerializerProvider serializerProvider ) | ||
throws IOException, JsonProcessingException | ||
{ | ||
jsonGenerator.writeString(new BigInteger(String.valueOf(integer)).toString(16).toUpperCase()); | ||
} | ||
} | ||
); | ||
} | ||
} | ||
~~~~~ | ||
|
||
Subsequently, the ObjectMapper, created from the Guice injector above, will apply the proper data bindings to serialize | ||
Integers as base 16 strings: | ||
|
||
~~~~~ | ||
mapper.writeValueAsString(new Integer(10)) ==> "A" | ||
~~~~~ | ||
|
||
Additional Guice Modules can be used when creating the Injector to automatically inject values into value objects | ||
being de-serialized. The @JacksonInject annotation can be used to trigger Guice driven injection. | ||
|
||
Here's an example of a value object where Guice injects three of the members on behalf of Jackson. The first | ||
uses the @JacksonInject annotation, the second uses @JacksonInject with a specific Named binding, and the | ||
third uses @JacksonInject combined with another annotation (@Ann). | ||
|
||
~~~~~ | ||
public class SomeBean { | ||
@JacksonInject | ||
private int one; | ||
@JacksonInject | ||
@Named("two") | ||
private int two; | ||
@JacksonInject | ||
@Ann | ||
private int three; | ||
@JsonProperty | ||
private int four; | ||
public boolean verify() { | ||
Assert.assertEquals(1, one); | ||
Assert.assertEquals(2, two); | ||
Assert.assertEquals(3, three); | ||
Assert.assertEquals(4, four); | ||
return true; | ||
} | ||
} | ||
~~~~~ | ||
|
||
The last, the fourth field, annotated with @JsonProperty uses standard ObjectMapper behavior unlike the other three | ||
which are injected by Guice. The following code snippet demonstrates Guice injection leading to a true return on the | ||
verify() method: | ||
|
||
|
||
~~~~~ | ||
final Injector injector = Guice.createInjector( | ||
new ObjectMapperModule(), | ||
new Module() | ||
{ | ||
@Override | ||
public void configure(Binder binder) | ||
{ | ||
binder.bind(Integer.class).toInstance(1); | ||
binder.bind(Integer.class).annotatedWith(Names.named("two")).toInstance(2); | ||
binder.bind(Integer.class).annotatedWith(Ann.class).toInstance(3); | ||
} | ||
} | ||
); | ||
final ObjectMapper mapper = injector.getInstance(ObjectMapper.class); | ||
mapper.readValue("{\"four\": 4}", SomeBean.class).verify(); | ||
~~~~~ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<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"> | ||
<!-- This module was also published with a richer model, Gradle metadata, --> | ||
<!-- which should be used instead. Do not delete the following line which --> | ||
<!-- is to indicate to Gradle or any Gradle module metadata file consumer --> | ||
<!-- that they should prefer consuming it instead. --> | ||
<!-- do_not_remove: published-with-gradle-metadata --> | ||
<modelVersion>4.0.0</modelVersion> | ||
<parent> | ||
<groupId>com.fasterxml.jackson.module</groupId> | ||
<artifactId>jackson-modules-base</artifactId> | ||
<version>2.16.0-SNAPSHOT</version> | ||
</parent> | ||
<artifactId>jackson-module-guice7</artifactId> | ||
<name>Jackson module: Guice 7+ (jakarta.inject)</name> | ||
<packaging>bundle</packaging> | ||
|
||
<description>Stuff to make integration with Guice 7+ a bit easier</description> | ||
<url>https://github.com/FasterXML/jackson-modules-base</url> | ||
|
||
<licenses> | ||
<license> | ||
<name>The Apache Software License, Version 2.0</name> | ||
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url> | ||
<distribution>repo</distribution> | ||
</license> | ||
</licenses> | ||
|
||
<properties> | ||
<version.guice>[7.0,8.0)</version.guice> | ||
|
||
<!-- Generate PackageVersion.java into this directory. --> | ||
<packageVersion.dir>com/fasterxml/jackson/module/guice7</packageVersion.dir> | ||
<packageVersion.package>${project.groupId}.guice7</packageVersion.package> | ||
<!-- default OSGi imports, exports should work fine --> | ||
</properties> | ||
|
||
<dependencies> | ||
<!-- Extends Jackson mapper, but also uses types from core, hence direct dep as well --> | ||
<dependency> | ||
<groupId>com.fasterxml.jackson.core</groupId> | ||
<artifactId>jackson-annotations</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.fasterxml.jackson.core</groupId> | ||
<artifactId>jackson-core</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.fasterxml.jackson.core</groupId> | ||
<artifactId>jackson-databind</artifactId> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.google.inject</groupId> | ||
<artifactId>guice</artifactId> | ||
<version>${version.guice}</version> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>com.google.code.maven-replacer-plugin</groupId> | ||
<artifactId>replacer</artifactId> | ||
</plugin> | ||
<!-- 14-Mar-2019, tatu: Add rudimentary JDK9+ module info. To build with JDK 8 | ||
will have to use `moduleInfoFile` as anything else requires JDK 9+ | ||
--> | ||
<plugin> | ||
<groupId>org.moditect</groupId> | ||
<artifactId>moditect-maven-plugin</artifactId> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
|
||
</project> |
114 changes: 114 additions & 0 deletions
114
guice7/src/main/java/com/fasterxml/jackson/module/guice7/GuiceAnnotationIntrospector.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
package com.fasterxml.jackson.module.guice; | ||
|
||
import com.fasterxml.jackson.annotation.JacksonInject; | ||
import com.fasterxml.jackson.databind.introspect.*; | ||
import com.google.inject.BindingAnnotation; | ||
import com.google.inject.Key; | ||
|
||
import jakarta.inject.Qualifier; | ||
import java.lang.annotation.Annotation; | ||
import java.util.Arrays; | ||
|
||
public class GuiceAnnotationIntrospector extends NopAnnotationIntrospector | ||
{ | ||
private static final long serialVersionUID = 1L; | ||
|
||
@Override // since 2.9 | ||
public JacksonInject.Value findInjectableValue(AnnotatedMember m) { | ||
Object id = _findGuiceInjectId(m); | ||
if (id == null) { | ||
return null; | ||
} | ||
return JacksonInject.Value.forId(id); | ||
} | ||
|
||
@Deprecated // since 2.9 | ||
@Override | ||
public Object findInjectableValueId(AnnotatedMember m) { | ||
return _findGuiceInjectId(m); | ||
} | ||
|
||
private Object _findGuiceInjectId(AnnotatedMember m) | ||
{ | ||
/* | ||
* We check on three kinds of annotations: @JacksonInject for types | ||
* that were actually created for Jackson, and @Inject (both Guice's | ||
* and jakarta.inject) for types that (for example) extend already | ||
* annotated objects. | ||
* | ||
* Postel's law: http://en.wikipedia.org/wiki/Robustness_principle | ||
*/ | ||
// 19-Apr-2017, tatu: Actually this is something that should not be done; | ||
// instead, pair of AnnotationIntrospector should be used... Leaving in | ||
// for now, however. | ||
if ((m.getAnnotation(JacksonInject.class) == null) && | ||
(m.getAnnotation(jakarta.inject.Inject.class) == null) && | ||
(m.getAnnotation(com.google.inject.Inject.class) == null)) | ||
{ | ||
return null; | ||
} | ||
|
||
final AnnotatedMember guiceMember; | ||
final Annotation guiceAnnotation; | ||
|
||
if ((m instanceof AnnotatedField) || (m instanceof AnnotatedParameter)) { | ||
/* On fields and parameters the @Qualifier annotation and type to | ||
* inject are the member itself, so, nothing to do here... | ||
*/ | ||
guiceMember = m; | ||
AnnotationMap anns = ((AnnotatedMember) m).getAllAnnotations(); | ||
guiceAnnotation = findBindingAnnotation(anns.annotations()); | ||
} else if (m instanceof AnnotatedMethod) { | ||
/* For method injection, the @Qualifier and type to inject are | ||
* specified on the parameter. Here, we only consider methods with | ||
* a single parameter. | ||
*/ | ||
final AnnotatedMethod a = (AnnotatedMethod) m; | ||
if (a.getParameterCount() != 1) { | ||
return null; | ||
} | ||
|
||
/* Jackson does not *YET* give us parameter annotations on methods, | ||
* only on constructors, henceforth we have to do a bit of work | ||
* ourselves! | ||
*/ | ||
guiceMember = a.getParameter(0); | ||
final Annotation[] annotations = a.getMember().getParameterAnnotations()[0]; | ||
guiceAnnotation = findBindingAnnotation(Arrays.asList(annotations)); | ||
} else { | ||
/* Ignore constructors */ | ||
return null; | ||
} | ||
|
||
/* Depending on whether we have an annotation (or not) return the | ||
* correct Guice key that Jackson will use to query the Injector. | ||
*/ | ||
if (guiceAnnotation == null) { | ||
// 19-Sep-2016, tatu: Used to pass `getGenericType()`, but that is now deprecated. | ||
// Looking at code in Guice Key, I don't think it does particularly good job | ||
// in resolving generic types, so this is probably safe... | ||
// return Key.get(guiceMember.getGenericType()); | ||
return Key.get((java.lang.reflect.Type) guiceMember.getRawType()); | ||
} | ||
// return Key.get(guiceMember.getGenericType(), guiceAnnotation); | ||
return Key.get((java.lang.reflect.Type) guiceMember.getRawType(), guiceAnnotation); | ||
} | ||
|
||
/* | ||
* We want to figure out if a @BindingAnnotation or @Qualifier | ||
* annotation are present on what we're trying to inject. | ||
* Those annotations are only possible on fields or parameters. | ||
*/ | ||
private Annotation findBindingAnnotation(Iterable<Annotation> annotations) | ||
{ | ||
for (Annotation annotation : annotations) { | ||
// Check on guice (BindingAnnotation) & jakarta (Qualifier) based injections | ||
if (annotation.annotationType().isAnnotationPresent(BindingAnnotation.class) || | ||
annotation.annotationType().isAnnotationPresent(Qualifier.class)) | ||
{ | ||
return annotation; | ||
} | ||
} | ||
return null; | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
guice7/src/main/java/com/fasterxml/jackson/module/guice7/GuiceInjectableValues.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.fasterxml.jackson.module.guice; | ||
|
||
import com.fasterxml.jackson.databind.BeanProperty; | ||
import com.fasterxml.jackson.databind.DeserializationContext; | ||
import com.fasterxml.jackson.databind.InjectableValues; | ||
import com.google.inject.Injector; | ||
import com.google.inject.Key; | ||
|
||
public class GuiceInjectableValues extends InjectableValues | ||
{ | ||
private final Injector injector; | ||
|
||
public GuiceInjectableValues(Injector injector) {this.injector = injector;} | ||
|
||
@Override | ||
public Object findInjectableValue( | ||
Object valueId, DeserializationContext ctxt, BeanProperty forProperty, Object beanInstance | ||
) | ||
{ | ||
return injector.getInstance((Key<?>) valueId); | ||
} | ||
} |
Oops, something went wrong.