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

Refactor SPI interfaces, use io.avaje.jsonb.spi.JsonbExtension + other breaking changes #246

Merged
merged 15 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/jdk-ea-stable.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

name: avaje-jsonb EA stable
name: JDK EA Stable

on:
push:
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ build/
*.project
*.class
.DS_Store
jsonb-generator/.factorypath
*.factorypath
jsonb-generator/io.avaje.jsonb.spi.JsonbExtension
6 changes: 4 additions & 2 deletions blackbox-test/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

requires static io.avaje.jsonb;
requires java.validation;
requires static io.avaje.spi;

provides io.avaje.jsonb.Jsonb.GeneratedComponent with org.example.jsonb.GeneratedJsonComponent;
}
provides io.avaje.jsonb.spi.JsonbExtension with org.example.customer.customtype.CustomTypeComponent, org.example.jsonb.GeneratedJsonComponent;

}
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package org.example.customer.customtype;

import io.avaje.jsonb.JsonAdapter;
import io.avaje.jsonb.JsonReader;
import io.avaje.jsonb.JsonWriter;
import io.avaje.jsonb.Jsonb;
import io.avaje.jsonb.spi.JsonbCustomizer;
import io.avaje.spi.ServiceProvider;

import io.avaje.jsonb.*;

/**
* Register via service loading.
*/
public class CustomTypeComponent implements JsonbComponent {
/** Register via service loading. */
@ServiceProvider
public class CustomTypeComponent implements JsonbCustomizer {

@Override
public void register(Jsonb.Builder builder) {
public void customize(Jsonb.Builder builder) {
builder.add(MyCustomScalarType.class, new CustomTypeAdapterWithStar().nullSafe());
}

Expand All @@ -26,6 +29,4 @@ public MyCustomScalarType fromJson(JsonReader reader) {
return MyCustomScalarType.of(encoded.substring(4)); // trim those stars
}
}

}

This file was deleted.

6 changes: 6 additions & 0 deletions jsonb-generator/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
<optional>true</optional>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-spi-service</artifactId>
<version>${spi.version}</version>
</dependency>

<dependency>
<groupId>io.avaje</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

final class Constants {

static final String META_INF_COMPONENT = "META-INF/services/io.avaje.jsonb.Jsonb$GeneratedComponent";
static final String META_INF_COMPONENT = "META-INF/services/io.avaje.jsonb.spi.JsonbExtension";
static final String JSONB_WILD = "io.avaje.jsonb.*";
static final String JSONB_SPI = "io.avaje.jsonb.spi.*";
static final String JSONB = "io.avaje.jsonb.Jsonb";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,13 @@ static boolean useEnhancedSwitch() {
}

static FileObject createMetaInfWriterFor(String interfaceType) throws IOException {
return filer().createResource(StandardLocation.CLASS_OUTPUT, "", interfaceType);

var serviceFile =
APContext.typeElement("io.avaje.spi.internal.ServiceProcessor") != null
? interfaceType.replace("META-INF/services/", "META-INF/generated-services/")
: interfaceType;

return filer().createResource(StandardLocation.CLASS_OUTPUT, "", serviceFile);
}

static void addImportedPrism(ImportPrism prism, Element element) {
Expand Down Expand Up @@ -101,15 +107,7 @@ static void validateModule(String fqn) {
boolean noInjectPlugin =
injectPresent && !moduleInfo.containsOnModulePath("io.avaje.jsonb.plugin");

var noProvides =
moduleInfo.provides().stream()
.flatMap(s -> s.implementations().stream())
.noneMatch(s -> s.contains(fqn));

var buildPluginAvailable = buildPluginAvailable();
if (noProvides && !buildPluginAvailable) {
logError(module, "Missing `provides io.avaje.jsonb.Jsonb.GeneratedComponent with %s;`", fqn);
}

final var noDirectJsonb =
moduleInfo.requires().stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ private void initialiseComponent() {
try {
componentWriter.initialise();
} catch (final IOException e) {
logError("Error creating writer for JsonbComponent", e);
logError("Error creating writer for JsonbCustomizer", e);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ void writeMetaInf() throws IOException {

private void writeRegister() {
writer.append(" @Override").eol();
writer.append(" public void register(Jsonb.Builder builder) {").eol();
writer.append(" public void customize(Jsonb.Builder builder) {").eol();
final List<String> strings = metaData.allFactories();
for (final String adapterFullName : strings) {
final String adapterShortName = Util.shortName(adapterFullName);
Expand Down Expand Up @@ -91,7 +91,7 @@ private void writeClassStart() {
writeMetaDataEntry(all);
writer.append("})").eol();

writer.append("public class %s implements Jsonb.GeneratedComponent {", shortName).eol().eol();
writer.append("public class %s implements GeneratedComponent {", shortName).eol().eol();
}

private void writeMetaDataEntry(List<String> entries) {
Expand Down
11 changes: 9 additions & 2 deletions jsonb-inject-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,22 @@
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-jsonb</artifactId>
<version>1.10-RC1</version>
<version>1.11</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>

<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-spi-service</artifactId>
<version>${spi.version}</version>
<optional>true</optional>
</dependency>

<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-inject</artifactId>
<version>9.12</version>
<version>10.0-RC7</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
package io.avaje.jsonb.inject;

import java.lang.reflect.Type;

import io.avaje.inject.BeanScopeBuilder;
import io.avaje.inject.spi.InjectPlugin;
import io.avaje.jsonb.Jsonb;
import io.avaje.jsonb.stream.BufferRecycleStrategy;
import io.avaje.spi.ServiceProvider;

/**
* Plugin for avaje inject that provides a default Jsonb instance.
*/
public final class DefaultJsonbProvider implements io.avaje.inject.spi.Plugin {
@ServiceProvider
public final class DefaultJsonbProvider implements InjectPlugin {

@Override
public Class<?>[] provides() {
return new Class<?>[]{Jsonb.class};
public Type[] provides() {
return new Type[]{Jsonb.class};
}

@Override
public void apply(BeanScopeBuilder builder) {
builder.provideDefault(null, Jsonb.class, () -> {
var props = builder.propertyPlugin();
var props = builder.configPlugin();

return Jsonb.builder()
.failOnUnknown(props.equalTo("jsonb.deserialize.failOnUnknown", "true"))
Expand Down
3 changes: 2 additions & 1 deletion jsonb-inject-plugin/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

requires transitive io.avaje.jsonb;
requires transitive io.avaje.inject;
requires static io.avaje.spi;

provides io.avaje.inject.spi.Plugin with io.avaje.jsonb.inject.DefaultJsonbProvider;
provides io.avaje.inject.spi.InjectExtension with io.avaje.jsonb.inject.DefaultJsonbProvider;
}

This file was deleted.

7 changes: 7 additions & 0 deletions jsonb/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@
<version>4.0.10</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>

<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-spi-service</artifactId>
<version>${spi.version}</version>
<optional>true</optional>
</dependency>

<dependency>
Expand Down
22 changes: 2 additions & 20 deletions jsonb/src/main/java/io/avaje/jsonb/Jsonb.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import io.avaje.jsonb.core.DefaultBootstrap;
import io.avaje.jsonb.spi.AdapterFactory;
import io.avaje.jsonb.spi.Bootstrap;
import io.avaje.jsonb.spi.JsonStreamAdapter;
import io.avaje.jsonb.spi.JsonbCustomizer;
import io.avaje.jsonb.spi.PropertyNames;
import io.avaje.jsonb.stream.BufferRecycleStrategy;
import io.avaje.jsonb.stream.JsonOutput;
Expand All @@ -13,8 +13,6 @@
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Type;
import java.util.Iterator;
import java.util.ServiceLoader;

/**
* Provides access to json adapters by type.
Expand Down Expand Up @@ -102,10 +100,6 @@ public interface Jsonb {
* }</pre>
*/
static Builder builder() {
Iterator<Bootstrap> bootstrapService = ServiceLoader.load(Bootstrap.class).iterator();
if (bootstrapService.hasNext()) {
return bootstrapService.next().builder();
}
return DefaultBootstrap.builder();
}

Expand Down Expand Up @@ -400,7 +394,7 @@ interface Builder {
/**
* Add a Component which can provide multiple JsonAdapters and or configuration.
*/
Builder add(JsonbComponent component);
Builder add(JsonbCustomizer component);

/**
* Add a JsonAdapter.Factory which provides JsonAdapters to use.
Expand All @@ -424,16 +418,4 @@ interface AdapterBuilder {
*/
JsonAdapter<?> build(Jsonb jsonb);
}

/**
* Components register JsonAdapters Jsonb.Builder
*/
@FunctionalInterface
interface GeneratedComponent extends JsonbComponent {

/**
* Register JsonAdapters with the Builder.
*/
void register(Builder builder);
}
}
17 changes: 0 additions & 17 deletions jsonb/src/main/java/io/avaje/jsonb/JsonbComponent.java

This file was deleted.

20 changes: 10 additions & 10 deletions jsonb/src/main/java/io/avaje/jsonb/core/DJsonb.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ final class DJsonb implements Jsonb {
if (adapter != null) {
this.io = adapter;
} else {
Iterator<AdapterFactory> iterator = ServiceLoader.load(AdapterFactory.class).iterator();
if (iterator.hasNext()) {
this.io = iterator.next().create(serializeNulls, serializeEmpty, failOnUnknown);
var adapterFactoryOptional = ExtensionLoader.adapterFactory();
if (adapterFactoryOptional.isPresent()) {
this.io = adapterFactoryOptional.get().create(serializeNulls, serializeEmpty, failOnUnknown);
} else {
this.io = new JsonStream(serializeNulls, serializeEmpty, failOnUnknown, strategy);
}
Expand Down Expand Up @@ -277,8 +277,8 @@ public <T> Builder add(Type type, JsonAdapter<T> jsonAdapter) {
}

@Override
public Builder add(JsonbComponent component) {
component.register(this);
public Builder add(JsonbCustomizer component) {
component.customize(this);
return this;
}

Expand All @@ -289,12 +289,12 @@ public Builder add(JsonAdapter.Factory factory) {
}

private void registerComponents() {
// first register all user defined JsonbComponent
for (JsonbComponent next : ServiceLoader.load(JsonbComponent.class)) {
next.register(this);
// first register all user defined JsonbCustomizer
for (JsonbCustomizer next : ExtensionLoader.customizers()) {
next.customize(this);
}
for (GeneratedComponent next : ServiceLoader.load(GeneratedComponent.class)) {
next.register(this);
for (GeneratedComponent next : ExtensionLoader.generatedComponents()) {
next.customize(this);
}
}

Expand Down
43 changes: 43 additions & 0 deletions jsonb/src/main/java/io/avaje/jsonb/core/ExtensionLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package io.avaje.jsonb.core;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.ServiceLoader;

import io.avaje.jsonb.spi.AdapterFactory;
import io.avaje.jsonb.spi.GeneratedComponent;
import io.avaje.jsonb.spi.JsonbCustomizer;
import io.avaje.jsonb.spi.JsonbExtension;

/** Load all the services using the common service interface. */
final class ExtensionLoader {

private static final List<GeneratedComponent> generatedComponents = new ArrayList<>();
private static final List<JsonbCustomizer> customizers = new ArrayList<>();
private static Optional<AdapterFactory> adapterFactory = Optional.empty();

static {
for (var spi : ServiceLoader.load(JsonbExtension.class)) {
if (spi instanceof GeneratedComponent) {
generatedComponents.add((GeneratedComponent) spi);
} else if (spi instanceof JsonbCustomizer) {
customizers.add((JsonbCustomizer) spi);
} else if (spi instanceof AdapterFactory) {
adapterFactory = Optional.of((AdapterFactory) spi);
}
}
}

static List<GeneratedComponent> generatedComponents() {
return generatedComponents;
}

static List<JsonbCustomizer> customizers() {
return customizers;
}

static Optional<AdapterFactory> adapterFactory() {
return adapterFactory;
}
}
2 changes: 1 addition & 1 deletion jsonb/src/main/java/io/avaje/jsonb/spi/AdapterFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/**
* Factory that is service loaded to create the adapter for underlying json parsing and generation.
*/
public interface AdapterFactory {
public interface AdapterFactory extends JsonbExtension {

/**
* Create the adapter to use for the underlying json parsing and generation.
Expand Down
Loading
Loading