Skip to content

Commit

Permalink
Merge pull request #285 from SentryMan/notNull
Browse files Browse the repository at this point in the history
Add BigInteger param  type mapping
  • Loading branch information
SentryMan authored Sep 13, 2023
2 parents 7848573 + 5b0c0a0 commit 29e8f15
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 32 deletions.
59 changes: 31 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ public class WidgetController {
}
```
## DI Usage
The annotation processor will generate controller adapters to register routes to Javalin/Helidon. The natural way to use the generated adapters is to get a DI library to find and wire them. This is what the examples below do; they use [Avaje-Inject](https://avaje.io/inject/) to do this. The AP will automatically detect the presence of avaje-inject and generate the class to use avaje-inject's `@Component` as the DI annotation.
The annotation processor will generate controller adapters to register routes to Javalin/Helidon. The natural way to use the generated adapters is to get a DI library to find and wire them. The AP will automatically detect the presence of avaje-inject and generate the class to use avaje-inject's `@Component` as the DI annotation.

There isn't a hard requirement to use Avaje for dependency injection. In the absence of avaje-inject, the generated class will use `@jakarta.inject.Singleton` or `@javax.inject.Singleton` depending on what's on the classpath. Any DI library that can find and wire the generated @Singleton beans can be used. You can even use Dagger2 or Guice to wire the controllers if you so desire.
There isn't a hard requirement to use [Avaje](https://avaje.io/inject/) for dependency injection. In the absence of avaje-inject, the generated class will use `@jakarta.inject.Singleton` or `@javax.inject.Singleton` depending on what's on the classpath. Any DI library that can find and wire the generated @Singleton beans can be used. You can even use Dagger2 or Guice to wire the controllers if you so desire.

To force the AP to generate with `@javax.inject.Singleton`(in the case where you have both jakarta and javax on the classpath), use the compiler arg `-AuseJavax=true`
```xml
Expand All @@ -93,22 +93,20 @@ To force the AP to generate with `@javax.inject.Singleton`(in the case where you

### Usage with Javalin

The annotation processor will generate controller classes implementing the Javalin `Plugin` interface, which means we can
get all the WebRoutes and register them with Javalin using:
The annotation processor will generate controller classes implementing the Javalin `Plugin` interface, which means we can register them with Javalin using:

```java
List<Plugin> routes = BeanScope.builder().build().list(Plugin.class);
List<Plugin> routes = ...; //retrieve using a DI framework

Javalin.create(cfg -> routes.forEach(cfg.plugins::register)).start();
```

### Usage with Helidon Nima
### Usage with Helidon SE (4.x)

The annotation processor will generate controller classes implementing the Helidon HttpService interface, which we can use
get all the services and register them with the Helidon `HttpRouting`.
The annotation processor will generate controller classes implementing the Helidon HttpFeature interface, which we can register with the Helidon `HttpRouting`.

```java
List<HttpFeature> routes = BeanScope.builder().build().list(HttpFeature.class);
List<HttpFeature> routes = ... //retrieve using a DI framework
final var builder = HttpRouting.builder();

routes.forEach(builder::addFeature);
Expand Down Expand Up @@ -153,14 +151,15 @@ public class WidgetController$Route implements Plugin {
}
```

### (Helidon Nima) The generated WidgetController$Route.java is:
### (Helidon SE) The generated WidgetController$Route.java is:

```java
@Generated("avaje-helidon-nima-generator")
@Singleton
@Generated("avaje-helidon-generator")
@Component
public class WidgetController$Route implements HttpFeature {

private final WidgetController controller;

public WidgetController$Route(WidgetController controller) {
this.controller = controller;
}
Expand All @@ -172,17 +171,19 @@ public class WidgetController$Route implements HttpFeature {
}

private void _getById(ServerRequest req, ServerResponse res) throws Exception {
res.status(OK_200);
var pathParams = req.path().pathParameters();
int id = asInt(pathParams.first("id").get());
var id = asInt(pathParams.first("id").get());
var result = controller.getById(id);
res.send(result);
}

private void _getAll(ServerRequest req, ServerResponse res) {
var pathParams = req.path().pathParameters();
private void _getAll(ServerRequest req, ServerResponse res) throws Exception {
res.status(OK_200);
var result = controller.getAll();
res.send(result);
}

}
```

Expand Down Expand Up @@ -225,21 +226,21 @@ public class WidgetController$Route implements Plugin {
}
```

### (Helidon Nima) The generated WidgetController$Route.java is:
### (Helidon SE) The generated WidgetController$Route.java is:

```java
@Generated("avaje-helidon-nima-generator")
@Generated("avaje-helidon-generator")
@Component
public class WidgetController$Route implements HttpFeature {

private final WidgetController controller;
private final JsonType<Widget> widgetJsonType;
private final JsonType<List<Widget>> listWidgetJsonType;
private final JsonType<WidgetController.Widget> widgetController$WidgetJsonType;
private final JsonType<List<WidgetController.Widget>> listWidgetController$WidgetJsonType;

public WidgetController$Route(WidgetController controller, Jsonb jsonB) {
public WidgetController$Route(WidgetController controller, Jsonb jsonb) {
this.controller = controller;
this.widgetJsonType = jsonB.type(Widget.class);
this.listWidgetJsonType = jsonB.type(Widget.class).list();
this.widgetController$WidgetJsonType = jsonb.type(WidgetController.Widget.class);
this.listWidgetController$WidgetJsonType = jsonb.type(WidgetController.Widget.class).list();
}

@Override
Expand All @@ -249,18 +250,20 @@ public class WidgetController$Route implements HttpFeature {
}

private void _getById(ServerRequest req, ServerResponse res) throws Exception {
res.status(OK_200);
var pathParams = req.path().pathParameters();
int id = asInt(pathParams.first("id").get());
var id = asInt(pathParams.first("id").get());
var result = controller.getById(id);
res.headers().contentType(HttpMediaType.APPLICATION_JSON);
widgetJsonType.toJson(result, JsonOutput.of(res));
res.headers().contentType(MediaTypes.APPLICATION_JSON);
widgetController$WidgetJsonType.toJson(result, JsonOutput.of(res));
}

private void _getAll(ServerRequest req, ServerResponse res) throws Exception {
var pathParams = req.path().pathParameters();
res.status(OK_200);
var result = controller.getAll();
res.headers().contentType(HttpMediaType.APPLICATION_JSON);
listWidgetJsonType.toJson(result, JsonOutput.of(res));
res.headers().contentType(MediaTypes.APPLICATION_JSON);
listWidgetController$WidgetJsonType.toJson(result, JsonOutput.of(res));
}

}
```
27 changes: 27 additions & 0 deletions http-api/src/main/java/io/avaje/http/api/PathTypeConversion.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.math.BigDecimal;
import java.time.*;
import java.math.BigInteger;
import java.util.List;
import java.util.Set;
import java.util.UUID;
Expand Down Expand Up @@ -131,6 +132,18 @@ public static boolean asBool(String value) {
return asBoolean(value);
}

/**
* Convert to BigInteger (not nullable).
*/
public static BigInteger asBigInteger(String value) {
checkNull(value);
try {
return new BigInteger(value);
} catch (RuntimeException e) {
throw new InvalidPathArgumentException(e);
}
}

/**
* Convert to BigDecimal (not nullable).
*/
Expand Down Expand Up @@ -296,6 +309,20 @@ public static BigDecimal toBigDecimal(String value) {
}
}

/**
* Convert to BigInteger (allowing nulls).
*/
public static BigInteger toBigInteger(String value) {
if (isNullOrEmpty(value)) {
return null;
}
try {
return new BigInteger(value);
} catch (Exception e) {
throw new InvalidTypeArgumentException(e);
}
}

/**
* Convert to Boolean (allowing nulls).
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ private static void add(TypeHandler h) {

add(new UuidHandler());
add(new BigDecimalHandler());
add(new BigDecimalHandler());
add(new LocalDateHandler());
add(new LocalTimeHandler());
add(new LocalDateTimeHandler());
Expand Down Expand Up @@ -269,6 +270,12 @@ static class BigDecimalHandler extends ObjectHandler {
}
}

static class BigIntegerHandler extends ObjectHandler {
BigIntegerHandler() {
super("java.math.BigInteger", "BigInteger");
}
}

static class LocalDateHandler extends ObjectHandler {
LocalDateHandler() {
super("java.time.LocalDate", "LocalDate");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,14 @@ void writeHandler(boolean requestScoped) {
} else {
writer.append(" private void _%s(ServerRequest req, ServerResponse res) throws Exception {", method.simpleName()).eol();
}

if (!isFilter) {
int statusCode = method.statusCode();
if (statusCode > 0) {
writer.append(" res.status(%s);", lookupStatusCode(statusCode)).eol();
}
}

final var bodyType = method.bodyType();
if (bodyType != null && !method.isErrorMethod() && !isFilter) {
if ("InputStream".equals(bodyType)) {
Expand Down Expand Up @@ -253,10 +261,6 @@ private boolean usesFormParams() {
}

private void writeContextReturn() {
int statusCode = method.statusCode();
if (statusCode > 0) {
writer.append(" res.status(%s);", lookupStatusCode(statusCode)).eol();
}
final var producesOp = Optional.ofNullable(method.produces());
if (producesOp.isEmpty() && !useJsonB) {
return;
Expand Down

0 comments on commit 29e8f15

Please sign in to comment.