Skip to content

Latest commit

 

History

History
209 lines (173 loc) · 8.73 KB

File metadata and controls

209 lines (173 loc) · 8.73 KB

Java → Go Migration Guide

This guide is the cookbook for porting an existing Firefly Java service (or a sibling .NET service) to the Go port. Each section maps a Java / .NET concept to its idiomatic Go translation.

Module references

Java                                 → Go
org.fireflyframework:firefly-common  → github.com/.../kernel
firefly-common-utils                 → utils
firefly-common-validators            → validators
firefly-web                          → web
firefly-common-cache                 → cache
firefly-otel-spring-boot-starter     → observability
firefly-common-data                  → data
firefly-common-cqrs                  → cqrs
firefly-common-eda                   → eda
firefly-event-sourcing-…             → eventsourcing
firefly-common-domain (orchestration)→ orchestration
firefly-common-rule-engine           → ruleengine
firefly-platform-plugins             → plugins
firefly-service-client               → client
firefly-config-server                → configserver
firefly-idp + firefly-idp-*          → idp / idpinternaldb / idpkeycloak / idpazuread / idpawscognito
firefly-ecm + firefly-ecm-*          → ecm / ecm{storage,esignature}*
firefly-notifications + …            → notifications / notifications{sendgrid,resend,twilio,firebase}
firefly-callbacks                    → callbacks
firefly-webhooks                     → webhooks
spring-boot @ConfigurationProperties → config
spring-boot SpringApplication        → lifecycle
spring-boot-starter-actuator         → actuator
spring @Scheduled                    → scheduling
resilience4j-*                       → resilience
spring-security                      → security
flyway                               → migrations
springdoc-openapi                    → openapi
spring MessageSource                 → i18n
spring ServerSentEvent               → sse
spring @Transactional                → transactional
spring-boot-starter-test             → testkit

New Spring-equivalent modules (added in 26.04.02)

The following modules close the gap with the Spring Boot stack and the PyFly sibling. Each is wire-shape compatible with its Java / .NET counterpart but expressed in idiomatic Go (constructor injection, explicit middleware composition).

Spring concept Go module + entry point
@ConfigurationProperties + YAML bind config.Load[T](ctx, sources...) / config.LoadFromProfile[T](...)
SpringApplication.run() lifecycle.New(name).OnStart(...).OnHTTP(":8080", mux).Run(ctx)
spring-boot-starter-actuator actuator.Mount(actuator.Config{...}) or core.ActuatorHandler(...)
@Scheduled(cron="0 9 * * MON-FRI") scheduler.Cron("name", "0 9 * * 1-5", run) / FixedRate(...) / FixedDelay(...)
@CircuitBreaker @RateLimiter @Bulkhead resilience.Chain(timeout, breaker, bulkhead).Execute(ctx, fn)
@PreAuthorize("hasRole('ADMIN')") security.NewFilterChain().Require("/admin/", "ADMIN").Middleware()
Flyway V001__init.sql migrations.Run(ctx, db, migrations.NewFSSource(fsys, "db"))
@RestController + springdoc openapi.New(info).Add(RouteDef{...}).Handler()
MessageSource.getMessage(...) bundle.T(locale, key, args) after i18n.LocaleMiddleware(bundle)
Spring ServerSentEvent w, _ := sse.NewWriter(rw, r, pingInterval); w.Send(sse.Event{...})
@Transactional transactional.WithTx(ctx, db, func(ctx) error { ... })
@SpringBootTest httptest.NewServer(BuildHandler()) + testkit.{SignHMAC,SpyBroker,MustEncode}

Reactive types

The Java framework uses Project Reactor; the .NET port uses Task/IAsyncEnumerable. Idiomatic Go does not have reactive streams.

Java Go
Mono<T> (T, error) with leading ctx context.Context
Flux<T> chan T or Go 1.23 iter.Seq[T]
Mono.error(new ResourceNotFound()) return zero, kernel.NewNotFound("…")
Mono.deferContextual(…) Read from context.Context
Schedulers / subscribeOn Goroutines + go fn()
Mono.timeout(...) context.WithTimeout(ctx, d)

Every Firefly Go method takes a leading ctx context.Context and respects its cancellation.

Error handling

Java Go
throw new ResourceNotFoundException(...) return kernel.NewNotFound("…")
@ControllerAdvice ProblemDetail handler web.ProblemMiddleware + web.ErrorHandler
ErrorEnvelope kernel.ProblemDetail
OperationResult<T> kernel.Result[T] (or just (T, error))

CQRS

// Java
@CommandHandler
public Mono<UserCreated> handle(CreateUser cmd) { … }

bus.send(new CreateUser("alice"))
   .doOnNext(this::publish)
   .subscribe();
// Go
cqrs.Register[CreateUser, UserCreated](bus, func(ctx context.Context, cmd CreateUser) (UserCreated, error) {
    // …
})
out, err := cqrs.Send[CreateUser, UserCreated](ctx, bus, CreateUser{Name: "alice"})

Validation is lifted to the message: Validate() error makes the type implement cqrs.Validatable. Caching: CacheTTL() time.Duration makes a query implement cqrs.Cacheable.

HTTP middleware

// Java (Spring WebFlux)
@Bean
WebFilter idempotencyFilter() { return new IdempotencyFilter(...); }
// Go
mux := http.NewServeMux()
// … register routes …
core := startercore.New(startercore.Config{AppName: "orders"})
http.ListenAndServe(":8080", core.Middleware()(mux))

core.Middleware() is a single func(http.Handler) http.Handler that wraps panic-recovering ProblemDetail rendering, correlation-id propagation, and idempotency.

Repositories

// Java (R2DBC)
public interface UserRepository extends R2dbcRepository<User, String> { }
// Go
type UserRepository interface {
    data.Repository[User, string]
}

repo := data.NewMemoryRepository[User, string](func(u User) string { return u.ID })

A pgx-backed data.Repository implementation is in scope for the next release; today services that talk to PostgreSQL define their own typed repository conforming to data.Repository[T, K].

Sagas

// Java
@Saga
class CheckoutSaga {
    @Step
    void reserveStock(...) { ... }
    @Compensation
    void releaseStock(...) { ... }
}
// Go
saga := orchestration.Saga{
    Name: "checkout",
    Steps: []orchestration.Step{
        {Name: "reserve", Execute: reserve, Compensate: release},
        {Name: "charge",  Execute: charge,  Compensate: refund},
    },
}
out, err := saga.Run(ctx)

Compensation policy maps directly: CompensateBestEffort (default) / CompensateStopOnError.

Idempotency

// Java
@Idempotent("Idempotency-Key")
@PostMapping("/orders")
Mono<Order> place(@RequestBody PlaceOrder cmd) { … }

In Go, idempotency is a middleware applied at the framework boundary — applied automatically by core.Middleware() for every POST/PUT/PATCH that carries an Idempotency-Key header.

Configuration

Java (Spring Boot YAML key) Go field
firefly.app.name startercore.Config.AppName
firefly.cache.adapter cache.Adapter injection
firefly.eda.broker eda.Broker injection
firefly.idempotency.ttl web.IdempotencyConfig.TTL

There is no application.yml parser in this release — services build their Config struct in main.go. A YAML mapper is on the CONFIGURATION.md roadmap.