Skip to content

Commit

Permalink
Support for JSONB version 2 (#762)
Browse files Browse the repository at this point in the history
  • Loading branch information
vojtechhabarta committed Dec 5, 2021
1 parent 34a4ffa commit a69a36b
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 43 deletions.
10 changes: 10 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,16 @@
<artifactId>javax.ws.rs-api</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>jakarta.json.bind</groupId>
<artifactId>jakarta.json.bind-api</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>javax.json.bind</groupId>
<artifactId>javax.json.bind-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>jakarta.activation</groupId>
<artifactId>jakarta.activation-api</artifactId>
Expand Down
17 changes: 16 additions & 1 deletion typescript-generator-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,13 @@
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
</dependency>
<dependency>
<groupId>javax.json.bind</groupId>
<artifactId>javax.json.bind-api</artifactId>
</dependency>
<dependency>
<groupId>jakarta.json.bind</groupId>
<artifactId>jakarta.json.bind-api</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>org.graalvm.js</groupId>
Expand Down Expand Up @@ -247,6 +250,17 @@
file="src/test/java/cz/habarta/typescript/generator/JaxrsV2ApplicationTest.java"
token="jakarta.ws.rs"
value="javax.ws.rs"/>
<copy
file="src/test/java/cz/habarta/typescript/generator/parser/JsonbParserTest.java"
tofile="src/test/java/cz/habarta/typescript/generator/parser/JsonbV1ParserTest.java"/>
<replace
file="src/test/java/cz/habarta/typescript/generator/parser/JsonbV1ParserTest.java"
token="JsonbParserTest"
value="JsonbV1ParserTest"/>
<replace
file="src/test/java/cz/habarta/typescript/generator/parser/JsonbV1ParserTest.java"
token="jakarta.json.bind"
value="javax.json.bind"/>
</target>
</configuration>
</execution>
Expand All @@ -259,6 +273,7 @@
<configuration>
<target>
<delete file="src/test/java/cz/habarta/typescript/generator/JaxrsV2ApplicationTest.java"/>
<delete file="src/test/java/cz/habarta/typescript/generator/parser/JsonbV1ParserTest.java"/>
</target>
</configuration>
</execution>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -350,32 +349,9 @@ private static List<String> getDefaultExcludedClassNames() {
);
}

@SuppressWarnings("unchecked")
static <A extends Annotation> A getRsAnnotation(AnnotatedElement annotatedElement, Class<A> jakartaAnnotationClass) {
final Class<?> javaxAnnotationClass = javax(jakartaAnnotationClass);
final A jakartaAnnotation = annotatedElement.getAnnotation(jakartaAnnotationClass);
if (jakartaAnnotation != null) {
return jakartaAnnotation;
} else {
final ClassLoader classLoader = jakartaAnnotationClass.getClassLoader();
final Object javaxAnnotation = annotatedElement.getAnnotation((Class<Annotation>)javaxAnnotationClass);
if (javaxAnnotation != null) {
return (A) Proxy.newProxyInstance(
classLoader,
new Class<?>[]{jakartaAnnotationClass},
(proxy, method, args) -> {
try {
final Method javaxMethod = javaxAnnotation.getClass().getMethod(method.getName());
return javaxMethod.invoke(javaxAnnotation);
} catch (ReflectiveOperationException e) {
return null;
}
}
);
} else {
return null;
}
}
return Utils.getMigratedAnnotation(annotatedElement, jakartaAnnotationClass, javaxAnnotationClass);
}

private static <T> Class<T> javax(Class<T> jakartaClass) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
import cz.habarta.typescript.generator.util.Pair;
import cz.habarta.typescript.generator.util.PropertyMember;
import cz.habarta.typescript.generator.util.Utils;
import jakarta.json.bind.annotation.JsonbCreator;
import jakarta.json.bind.annotation.JsonbProperty;
import jakarta.json.bind.annotation.JsonbTransient;
import jakarta.json.bind.annotation.JsonbVisibility;
import jakarta.json.bind.config.PropertyNamingStrategy;
import jakarta.json.bind.config.PropertyVisibilityStrategy;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
Expand All @@ -27,6 +33,7 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand All @@ -40,12 +47,6 @@
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.json.bind.annotation.JsonbCreator;
import javax.json.bind.annotation.JsonbProperty;
import javax.json.bind.annotation.JsonbTransient;
import javax.json.bind.annotation.JsonbVisibility;
import javax.json.bind.config.PropertyNamingStrategy;
import javax.json.bind.config.PropertyVisibilityStrategy;

// simplified+dependency free version of apache johnzon JsonbAccessMode
public class JsonbParser extends ModelParser {
Expand Down Expand Up @@ -142,7 +143,7 @@ private JsonbPropertyExtractor(

private List<PropertyModel> visit(final Class<?> clazz) {
return Stream.of(clazz.getConstructors())
.filter(it -> it.isAnnotationPresent(JsonbCreator.class))
.filter(it -> getJsonbAnnotation(it, JsonbCreator.class) != null)
.findFirst()
.map(it -> new ArrayList<>(Stream.concat(visitConstructor(it), visitClass(clazz).stream())
.collect(Collectors.toMap(PropertyModel::getName, Function.identity(), (a, b) -> a)) // merge models
Expand All @@ -161,7 +162,7 @@ private Stream<PropertyModel> visitConstructor(final Constructor<?> constructor)
final Type type = it.getValue2();
final Parameter parameter = it.getValue1();
final Optional<JsonbProperty> property = Optional.ofNullable(
parameter.getAnnotation(JsonbProperty.class));
getJsonbAnnotation(parameter, JsonbProperty.class));
final PropertyMember propertyMember = new PropertyMember(
parameter, it.getValue2(), parameter.getAnnotatedType(), parameter::getAnnotation);
return JsonbParser.this.processTypeAndCreateProperty(
Expand Down Expand Up @@ -561,7 +562,7 @@ public DefaultPropertyVisibilityStrategy(ClassLoader classLoader) {

@Override
public boolean isVisible(final Field field) {
if (field.getAnnotation(JsonbProperty.class) != null) {
if (getJsonbAnnotation(field, JsonbProperty.class) != null) {
return true;
}
final PropertyVisibilityStrategy strategy = strategies.computeIfAbsent(
Expand All @@ -577,7 +578,7 @@ public boolean isVisible(final Method method) {
}

private PropertyVisibilityStrategy visibilityStrategy(final Class<?> type) {
JsonbVisibility visibility = type.getAnnotation(JsonbVisibility.class);
JsonbVisibility visibility = getJsonbAnnotation(type, JsonbVisibility.class);
if (visibility != null) {
try {
return visibility.value().getConstructor().newInstance();
Expand All @@ -587,7 +588,7 @@ private PropertyVisibilityStrategy visibilityStrategy(final Class<?> type) {
}
Package p = type.getPackage();
while (p != null) {
visibility = p.getAnnotation(JsonbVisibility.class);
visibility = getJsonbAnnotation(p, JsonbVisibility.class);
if (visibility != null) {
try {
return visibility.value().getConstructor().newInstance();
Expand Down Expand Up @@ -734,7 +735,7 @@ private static <T extends Annotation> T getClassOrPackageAnnotation(final Field
}

private static <T extends Annotation> T getDirectAnnotation(final AnnotatedElement holder, final Class<T> api) {
final T annotation = holder.getAnnotation(api);
final T annotation = getJsonbAnnotation(holder, api);
if (annotation != null) {
return annotation;
}
Expand All @@ -744,21 +745,21 @@ private static <T extends Annotation> T getDirectAnnotation(final AnnotatedEleme
private static <T extends Annotation> T getIndirectAnnotation(final Class<T> api,
final Supplier<Class<?>> ownerSupplier,
final Supplier<Package> packageSupplier) {
final T ownerAnnotation = ownerSupplier.get().getAnnotation(api);
final T ownerAnnotation = getJsonbAnnotation(ownerSupplier.get(), api);
if (ownerAnnotation != null) {
return ownerAnnotation;
}
final Package pck = packageSupplier.get();
if (pck != null) {
return pck.getAnnotation(api);
return getJsonbAnnotation(pck, api);
}
return null;
}

public static <T extends Annotation> T findMeta(final Annotation[] annotations, final Class<T> api) {
for (final Annotation a : annotations) {
final Class<? extends Annotation> userType = a.annotationType();
final T aa = userType.getAnnotation(api);
final T aa = getJsonbAnnotation(userType, api);
if (aa != null) {
boolean overriden = false;
final Map<String, Method> mapping = new HashMap<String, Method>();
Expand Down Expand Up @@ -836,4 +837,27 @@ public Annotation[] getDeclaredAnnotations() {
return parameter.getDeclaredAnnotations();
}
}

static <A extends Annotation> A getJsonbAnnotation(AnnotatedElement annotatedElement, Class<A> jakartaAnnotationClass) {
final Class<?> javaxAnnotationClass = javax(jakartaAnnotationClass);
return Utils.getMigratedAnnotation(annotatedElement, jakartaAnnotationClass, javaxAnnotationClass);
}

private static <T> Class<T> javax(Class<T> jakartaClass) {
@SuppressWarnings("unchecked")
final Class<T> cls = (Class<T>) javaxClasses.get().get(jakartaClass);
return cls;
}

private static final Supplier<Map<Class<?>, Class<?>>> javaxClasses = Utils.memoize(() -> {
final Map<Class<?>, Class<?>> map = new LinkedHashMap<>();
map.put(jakarta.json.bind.annotation.JsonbCreator.class, javax.json.bind.annotation.JsonbCreator.class);
map.put(jakarta.json.bind.annotation.JsonbProperty.class, javax.json.bind.annotation.JsonbProperty.class);
map.put(jakarta.json.bind.annotation.JsonbTransient.class, javax.json.bind.annotation.JsonbTransient.class);
map.put(jakarta.json.bind.annotation.JsonbVisibility.class, javax.json.bind.annotation.JsonbVisibility.class);
map.put(jakarta.json.bind.config.PropertyNamingStrategy.class, javax.json.bind.config.PropertyNamingStrategy.class);
map.put(jakarta.json.bind.config.PropertyVisibilityStrategy.class, javax.json.bind.config.PropertyVisibilityStrategy.class);
return map;
});

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.ArrayDeque;
import java.util.ArrayList;
Expand Down Expand Up @@ -224,6 +225,33 @@ public static List<Annotation> getRepeatableAnnotation(Annotation directAnnotati
return repeatableAnnotations;
}

@SuppressWarnings("unchecked")
public static <A extends Annotation> A getMigratedAnnotation(AnnotatedElement annotatedElement, Class<A> annotationClass, Class<?> fallbackAnnotationClass) {
final A annotation = annotatedElement.getAnnotation(annotationClass);
if (annotation != null) {
return annotation;
}
if (fallbackAnnotationClass != null) {
final ClassLoader classLoader = annotationClass.getClassLoader();
final Object fallbackAnnotation = annotatedElement.getAnnotation((Class<Annotation>)fallbackAnnotationClass);
if (fallbackAnnotation != null) {
return (A) Proxy.newProxyInstance(
classLoader,
new Class<?>[]{annotationClass},
(proxy, method, args) -> {
try {
final Method fallbackMethod = fallbackAnnotation.getClass().getMethod(method.getName());
return fallbackMethod.invoke(fallbackAnnotation);
} catch (ReflectiveOperationException e) {
return null;
}
}
);
}
}
return null;
}

public static Type replaceRawClassInType(Type type, Class<?> newClass) {
if (type instanceof ParameterizedType) {
final ParameterizedType parameterizedType = (ParameterizedType) type;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import cz.habarta.typescript.generator.Settings;
import cz.habarta.typescript.generator.TestUtils;
import cz.habarta.typescript.generator.TypeScriptGenerator;
import jakarta.json.bind.annotation.JsonbCreator;
import jakarta.json.bind.annotation.JsonbProperty;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Collection;
Expand All @@ -14,8 +16,6 @@
import java.util.Map;
import java.util.OptionalInt;
import java.util.UUID;
import javax.json.bind.annotation.JsonbCreator;
import javax.json.bind.annotation.JsonbProperty;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
Expand Down

0 comments on commit a69a36b

Please sign in to comment.