Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
22 changes: 22 additions & 0 deletions http-inject-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,28 @@
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.javalin</groupId>
<artifactId>javalin</artifactId>
<version>6.7.0</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.avaje</groupId>
<artifactId>avaje-jex</artifactId>
<version>3.3</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.helidon.webserver</groupId>
<artifactId>helidon-webserver</artifactId>
<version>4.3.2</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>

</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package io.avaje.http.inject;

import static java.util.stream.Collectors.joining;

import io.avaje.http.api.ValidationException;
import io.helidon.webserver.http.HttpFeature;
import io.helidon.webserver.http.HttpRouting.Builder;
import io.helidon.webserver.http.ServerRequest;
import io.helidon.webserver.http.ServerResponse;

public class HelidonHandler implements HttpFeature {

@Override
public void setup(Builder routing) {

routing.error(ValidationException.class, this::handle);
}

private void handle(ServerRequest req, ServerResponse res, ValidationException exception) {
var violations = exception.getErrors();

int violationCount = violations.size();
String violationList =
violations.stream()
.map(violation -> "'" + violation.getField() + "' " + violation.getMessage())
.collect(joining("\n"));

res.status(exception.getStatus())
.send(
String.format(
"Bad Request [%s validation violations: \n%s]", violationCount, violationList)
.getBytes());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package io.avaje.http.inject;

import io.avaje.http.api.AvajeJavalinPlugin;
import io.avaje.inject.BeanScopeBuilder;
import io.avaje.inject.spi.InjectPlugin;
import io.avaje.inject.spi.PluginProvides;
import io.avaje.jex.Routing.HttpService;
import io.avaje.spi.ServiceProvider;
import io.helidon.webserver.http.HttpFeature;

/** Plugin for avaje inject that provides a default Validator Handler */
@ServiceProvider
@PluginProvides(
providesStrings = {
"io.helidon.webserver.http.HttpFeature",
"io.avaje.http.api.AvajeJavalinPlugin",
"io.avaje.jex.Routing.HttpService",
})
public final class HttpValidatorHandler implements InjectPlugin {

enum Server {
HELIDON("io.helidon.webserver.http.HttpFeature"),
JAVALIN("io.javalin.plugin.Plugin"),
JEX("io.avaje.jex.Routing.HttpService");

String register;

Server(String register) {
this.register = register;
}
}

private static final Server type = server();

private static Server server() {

for (var register : Server.values()) {

try {
Class.forName(register.register);
return register;
} catch (ClassNotFoundException e) {
continue;
}
}

return null;
}

@Override
public void apply(BeanScopeBuilder builder) {
if (type == null) {
return;
}
switch (type) {
case HELIDON:
builder.provideDefault(HttpFeature.class, HelidonHandler::new);
break;
case JAVALIN:
builder.provideDefault(AvajeJavalinPlugin.class, JavalinHandler::new);
break;
case JEX:
builder.provideDefault(HttpService.class, JexHandler::new);
break;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.avaje.http.inject;

import static java.util.stream.Collectors.joining;

import java.util.List;

import io.avaje.http.api.AvajeJavalinPlugin;
import io.avaje.http.api.ValidationException;
import io.javalin.config.JavalinConfig;
import io.javalin.http.Context;

public class JavalinHandler extends AvajeJavalinPlugin {
@Override
public void onStart(JavalinConfig config) {
config.router.mount(r -> r.exception(ValidationException.class, this::handler));
}

private void handler(ValidationException ex, Context ctx) {

var json = ctx.status(ex.getStatus()).jsonMapper();

List<ValidationException.Violation> violations = ex.getErrors();
if (json == null) {
int violationCount = violations.size();
String violationList =
violations.stream()
.map(violation -> "'" + violation.getField() + "' " + violation.getMessage())
.collect(joining("\n"));

// return a plain-text error message
ctx.result(
String.format(
"Bad Request [%s validation violations: \n%s]", violationCount, violationList));
return;
}
ctx.json(new ValidationResponse(violations));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package io.avaje.http.inject;

import static java.util.stream.Collectors.joining;

import java.util.List;

import io.avaje.http.api.ValidationException;
import io.avaje.jex.Routing;
import io.avaje.jex.Routing.HttpService;
import io.avaje.jex.http.Context;

public class JexHandler implements HttpService {

@Override
public void add(Routing arg0) {

arg0.error(ValidationException.class, this::handler);
}

private void handler(Context ctx, ValidationException ex) {

var json = ctx.status(ex.getStatus()).jsonService();

List<ValidationException.Violation> violations = ex.getErrors();
if (json == null) {
int violationCount = violations.size();
String violationList =
violations.stream()
.map(violation -> "'" + violation.getField() + "' " + violation.getMessage())
.collect(joining("\n"));

// return a plain-text error message
ctx.text(
String.format(
"Bad Request [%s validation violations: \n%s]", violationCount, violationList));
return;
}
ctx.json(new ValidationResponse(violations));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.avaje.http.inject;

import java.util.List;

import io.avaje.http.api.ValidationException.Violation;

public class ValidationResponse {

private static String type = "https://avaje.io/http/#bean-validation";
private static String title = "Failed Constraints";
private List<Violation> errors;

public ValidationResponse(List<Violation> errors) {
this.errors = errors;
}

public String type() {
return type;
}

public String title() {
return title;
}

public List<Violation> errors() {
return errors;
}
}
9 changes: 7 additions & 2 deletions http-inject-plugin/src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import io.avaje.http.inject.DefaultResolverProvider;
import io.avaje.http.inject.HttpValidatorHandler;

module io.avaje.http.plugin {

requires io.avaje.http.api;
requires io.avaje.inject;
requires static io.avaje.spi;

provides io.avaje.inject.spi.InjectExtension with io.avaje.http.inject.DefaultResolverProvider;
requires static io.avaje.jex;
requires static io.javalin;
requires static io.helidon.webserver;
provides io.avaje.inject.spi.InjectExtension with DefaultResolverProvider, HttpValidatorHandler;
}
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
<module>http-client</module>
<module>http-client-gson-adapter</module>
<module>http-client-moshi-adapter</module>
<module>http-inject-plugin</module>
<module>http-generator-core</module>
<module>http-generator-javalin</module>
<module>http-generator-sigma</module>
Expand All @@ -67,6 +66,7 @@
<jdk>[21,)</jdk>
</activation>
<modules>
<module>http-inject-plugin</module>
<module>htmx-nima</module>
<module>htmx-nima-jstache</module>
<module>http-generator-helidon</module>
Expand Down