Skip to content

Commit

Permalink
Refactor SPI interfaces, use io.avaje.jsonb.spi.JsonbExtension + othe…
Browse files Browse the repository at this point in the history
…r breaking changes (#246)

* refactor SPI interfaces

* remove hard spi dependency

* cancel rename

* Update pom.xml

* remove generated-services registration

* f

* revert spi changes

* remove spi from blackbox

* fix meta-inf module loading

* rename customize

* fix services not appending

* Remove @service from JsonbExtension and add some javadoc

---------

Co-authored-by: Rob Bygrave <robin.bygrave@gmail.com>
  • Loading branch information
SentryMan and rbygrave authored Jun 25, 2024
1 parent 8357afd commit 3a175ac
Show file tree
Hide file tree
Showing 24 changed files with 153 additions and 89 deletions.
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
5 changes: 3 additions & 2 deletions blackbox-test/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
requires static io.avaje.jsonb;
requires java.validation;

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
Expand Up @@ -2,6 +2,7 @@


import io.avaje.jsonb.*;
import io.avaje.jsonb.spi.JsonbComponent;

/**
* Register via service loading.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

final class ComponentReader {

Expand All @@ -24,14 +25,18 @@ final class ComponentReader {
}

void read() {
String componentFullName = loadMetaInfServices();
if (componentFullName != null) {
TypeElement moduleType = typeElement(componentFullName);
if (moduleType != null) {
componentMetaData.setFullName(componentFullName);
readMetaData(moduleType);
}
}
loadMetaInf().stream()
.map(APContext::typeElement)
.filter(Objects::nonNull)
.filter(t -> "io.avaje.jsonb.spi.GeneratedComponent".equals(t.getSuperclass().toString()))
.findFirst()
.ifPresent(
moduleType -> {
if (moduleType != null) {
componentMetaData.setFullName(moduleType.getQualifiedName().toString());
readMetaData(moduleType);
}
});
}

/**
Expand All @@ -56,11 +61,6 @@ private void readMetaData(TypeElement moduleType) {
}
}

private String loadMetaInfServices() {
final List<String> lines = loadMetaInf();
return lines.isEmpty() ? null : lines.get(0);
}

private List<String> loadMetaInf() {
try {
FileObject fileObject = processingEnv()
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 @@ -108,7 +108,7 @@ static void validateModule(String fqn) {

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

final var noDirectJsonb =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@
import static io.avaje.jsonb.generator.ProcessingContext.createMetaInfWriterFor;
import static io.avaje.jsonb.generator.APContext.createSourceFile;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Writer;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import javax.tools.FileObject;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;

final class SimpleComponentWriter {

Expand Down Expand Up @@ -48,14 +51,36 @@ void write() throws IOException {
}

void writeMetaInf() throws IOException {
var services = readExistingMetaInfServices();
final FileObject fileObject = createMetaInfWriterFor(Constants.META_INF_COMPONENT);
if (fileObject != null) {
services.add(metaData.fullName());
final Writer writer = fileObject.openWriter();
writer.write(metaData.fullName());
writer.write(String.join("\n", services));
writer.close();
}
}

private static Set<String> readExistingMetaInfServices() {
var services = new TreeSet<String>();
try (final var file =
APContext.filer()
.getResource(StandardLocation.CLASS_OUTPUT, "", Constants.META_INF_COMPONENT)
.toUri()
.toURL()
.openStream();
final var buffer = new BufferedReader(new InputStreamReader(file)); ) {

String line;
while ((line = buffer.readLine()) != null) {
line.replaceAll("\\s", "").replace(",", "\n").lines().forEach(services::add);
}
} catch (Exception e) {
// not a critical error
}
return services;
}

private void writeRegister() {
writer.append(" @Override").eol();
writer.append(" public void register(Jsonb.Builder builder) {").eol();
Expand Down Expand Up @@ -91,7 +116,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
6 changes: 3 additions & 3 deletions jsonb-inject-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@
<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-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,26 @@
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;

/**
* Plugin for avaje inject that provides a default Jsonb instance.
*/
public final class DefaultJsonbProvider implements io.avaje.inject.spi.Plugin {
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
2 changes: 1 addition & 1 deletion jsonb-inject-plugin/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
requires transitive io.avaje.jsonb;
requires transitive io.avaje.inject;

provides io.avaje.inject.spi.Plugin with io.avaje.jsonb.inject.DefaultJsonbProvider;
provides io.avaje.inject.spi.InjectExtension with io.avaje.jsonb.inject.DefaultJsonbProvider;
}
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
20 changes: 1 addition & 19 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.JsonbComponent;
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 @@ -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.

10 changes: 5 additions & 5 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 @@ -290,10 +290,10 @@ public Builder add(JsonAdapter.Factory factory) {

private void registerComponents() {
// first register all user defined JsonbComponent
for (JsonbComponent next : ServiceLoader.load(JsonbComponent.class)) {
for (JsonbComponent next : ExtensionLoader.userComponents()) {
next.register(this);
}
for (GeneratedComponent next : ServiceLoader.load(GeneratedComponent.class)) {
for (GeneratedComponent next : ExtensionLoader.generatedComponents()) {
next.register(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.JsonbComponent;
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<JsonbComponent> userComponents = 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 JsonbComponent) {
userComponents.add((JsonbComponent) spi);
} else if (spi instanceof AdapterFactory) {
adapterFactory = Optional.of((AdapterFactory) spi);
}
}
}

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

static List<JsonbComponent> userComponents() {
return userComponents;
}

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
15 changes: 0 additions & 15 deletions jsonb/src/main/java/io/avaje/jsonb/spi/Bootstrap.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package io.avaje.jsonb.spi;

/** Component interface registers generated JsonAdapters to the Jsonb.Builder */
@FunctionalInterface
public interface GeneratedComponent extends JsonbComponent, JsonbExtension {}
Loading

0 comments on commit 3a175ac

Please sign in to comment.