Modern, JVM-based framework for building modular, easily testable microservice and serverless applications with compile-time DI and fast startup.
—
Micronaut provides comprehensive support for serverless functions with integration for AWS Lambda, Google Cloud Functions, Azure Functions, and local function execution.
Define functions using the standard Java Function interface.
/**
* Simple function bean
*/
@FunctionBean("hello")
public class HelloFunction implements Function<String, String> {
@Override
public String apply(String input) {
return "Hello " + input;
}
}
/**
* Function with dependency injection
*/
@FunctionBean("userProcessor")
public class UserProcessorFunction implements Function<UserRequest, UserResponse> {
private final UserService userService;
public UserProcessorFunction(UserService userService) {
this.userService = userService;
}
@Override
public UserResponse apply(UserRequest request) {
User user = userService.processUser(request);
return new UserResponse(user.getId(), user.getName());
}
}Create functions that return reactive types for asynchronous processing.
/**
* Reactive function implementations
*/
@FunctionBean("asyncProcessor")
public class AsyncProcessorFunction implements Function<ProcessRequest, Single<ProcessResponse>> {
private final ProcessingService processingService;
public AsyncProcessorFunction(ProcessingService processingService) {
this.processingService = processingService;
}
@Override
public Single<ProcessResponse> apply(ProcessRequest request) {
return processingService.processAsync(request)
.map(result -> new ProcessResponse(result.getId(), result.getStatus()));
}
}
/**
* Streaming function
*/
@FunctionBean("dataStream")
public class DataStreamFunction implements Function<Publisher<DataInput>, Publisher<DataOutput>> {
@Override
public Publisher<DataOutput> apply(Publisher<DataInput> input) {
return Flowable.fromPublisher(input)
.map(this::transform)
.filter(Objects::nonNull);
}
private DataOutput transform(DataInput input) {
// Transform input to output
return new DataOutput(input.getValue().toUpperCase());
}
}Create functions that handle HTTP requests and responses.
/**
* HTTP function handling
*/
@FunctionBean("httpHandler")
public class HttpHandlerFunction implements Function<HttpRequest<?>, HttpResponse<?>> {
@Override
public HttpResponse<?> apply(HttpRequest<?> request) {
String method = request.getMethod().toString();
String path = request.getPath();
Map<String, Object> response = Map.of(
"method", method,
"path", path,
"timestamp", Instant.now().toString()
);
return HttpResponse.ok(response);
}
}
/**
* Typed HTTP function
*/
@FunctionBean("apiEndpoint")
public class ApiEndpointFunction implements Function<ApiRequest, Single<ApiResponse>> {
private final ApiService apiService;
public ApiEndpointFunction(ApiService apiService) {
this.apiService = apiService;
}
@Override
public Single<ApiResponse> apply(ApiRequest request) {
return apiService.handleRequest(request)
.map(result -> new ApiResponse(result, "success"));
}
}Deploy functions as AWS Lambda functions with event handling.
/**
* AWS Lambda event handling
*/
@FunctionBean("s3Handler")
public class S3EventHandler implements Function<S3Event, String> {
private final S3Service s3Service;
public S3EventHandler(S3Service s3Service) {
this.s3Service = s3Service;
}
@Override
public String apply(S3Event event) {
for (S3EventNotification.S3EventNotificationRecord record : event.getRecords()) {
String bucketName = record.getS3().getBucket().getName();
String objectKey = record.getS3().getObject().getKey();
s3Service.processObject(bucketName, objectKey);
}
return "Processed " + event.getRecords().size() + " records";
}
}
/**
* API Gateway Lambda function
*/
@FunctionBean("apiGateway")
public class ApiGatewayFunction
implements Function<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
@Override
public APIGatewayProxyResponseEvent apply(APIGatewayProxyRequestEvent request) {
String httpMethod = request.getHttpMethod();
String path = request.getPath();
String body = request.getBody();
// Process the request
Map<String, Object> responseBody = Map.of(
"message", "Request processed",
"method", httpMethod,
"path", path
);
return APIGatewayProxyResponseEvent.builder()
.withStatusCode(200)
.withHeaders(Map.of("Content-Type", "application/json"))
.withBody(toJson(responseBody))
.build();
}
}Configure function deployment and runtime settings.
/**
* Function configuration
*/
@ConfigurationProperties("function")
public class FunctionConfiguration {
private String runtime = "java11";
private int timeout = 30;
private int memorySize = 512;
private Map<String, String> environment = new HashMap<>();
// getters and setters
}
/**
* AWS-specific configuration
*/
@ConfigurationProperties("aws.lambda")
public class LambdaConfiguration {
private String role;
private String functionName;
private String handler;
private List<String> layers = new ArrayList<>();
// getters and setters
}Test functions locally during development.
/**
* Local function testing
*/
@Singleton
public class FunctionTestRunner {
private final ApplicationContext applicationContext;
public FunctionTestRunner(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public <T, R> R executeFunction(String functionName, T input, Class<R> returnType) {
Function<T, R> function = applicationContext.getBean(Function.class,
Qualifiers.byName(functionName));
return function.apply(input);
}
public <T> void executeVoidFunction(String functionName, T input) {
Consumer<T> function = applicationContext.getBean(Consumer.class,
Qualifiers.byName(functionName));
function.accept(input);
}
}Optimize functions for minimal cold start times.
/**
* Cold start optimization
*/
@Introspected
@Serdeable
public class OptimizedFunction implements Function<OptimizedRequest, OptimizedResponse> {
// Use @Introspected for compile-time reflection
// Use @Serdeable for compile-time serialization
@Override
public OptimizedResponse apply(OptimizedRequest request) {
// Function logic optimized for fast startup
return new OptimizedResponse(process(request.getData()));
}
private String process(String data) {
// Minimal processing to reduce cold start impact
return data.toUpperCase();
}
}// Function annotations
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface FunctionBean {
String value();
}
// Core function interfaces
public interface Function<T, R> {
R apply(T t);
}
public interface Consumer<T> {
void accept(T t);
}
public interface Supplier<T> {
T get();
}
public interface BiFunction<T, U, R> {
R apply(T t, U u);
}
// HTTP function types
public interface HttpRequest<B> extends HttpMessage<B> {
HttpMethod getMethod();
URI getUri();
String getPath();
HttpParameters getParameters();
HttpHeaders getHeaders();
Optional<B> getBody();
}
public interface HttpResponse<B> extends HttpMessage<B> {
HttpStatus getStatus();
int code();
String reason();
HttpHeaders getHeaders();
Optional<B> getBody();
static <T> MutableHttpResponse<T> ok(T body);
static <T> MutableHttpResponse<T> created(T body);
static MutableHttpResponse<String> badRequest(String error);
}
// AWS Lambda types (when using AWS integration)
public class S3Event {
public List<S3EventNotificationRecord> getRecords();
}
public class APIGatewayProxyRequestEvent {
public String getHttpMethod();
public String getPath();
public String getBody();
public Map<String, String> getHeaders();
public Map<String, String> getQueryStringParameters();
}
public class APIGatewayProxyResponseEvent {
public static Builder builder();
public static class Builder {
public Builder withStatusCode(int statusCode);
public Builder withHeaders(Map<String, String> headers);
public Builder withBody(String body);
public APIGatewayProxyResponseEvent build();
}
}
// Function context for runtime information
public interface FunctionContext {
String getFunctionName();
String getFunctionVersion();
int getRemainingTimeInMillis();
int getMaxMemoryInMB();
String getRequestId();
}Install with Tessl CLI
npx tessl i tessl/maven-micronaut