SparkJava using Kotlin and WebSockets - websocket

I am trying out Kotlin with SparkJava, and having trouble implementing the WebSockets routes. I am trying to follow the WebSockets example available on the SparkJava website (http://sparkjava.com/tutorials/websocket-chat), and whilst I can get the OnWebSocketConnect and OnWebSocketMessage elements to work, the OnWebSocketClose is not picked up.
I have implemented this in Java to double check that it is not a browser issues, and the Java implementation works fine...so this appears to be something specific to the way Kotlin is interpreting the OnWebSocketClose annotation.
My code looks like the following
import spark.Spark.*
import org.eclipse.jetty.websocket.api.Session
import org.eclipse.jetty.websocket.api.annotations.*;
fun main(args: Array<String>) {
staticFileLocation("/public")
webSocket("/chat", WSHandler::class.java)
init()
}
#WebSocket
class WSHandler {
#OnWebSocketConnect
fun connected(session: Session) = println("session connected")
#OnWebSocketClose
fun closed(session: Session, statusCode: Int, reason: String) = println("closed sessions")
#OnWebSocketMessage
fun message(session: Session, message: String) = println("Got: $message")
}
The html / javascript etc are as per the tutorial on the SparkJava website.

There is an error during invocation of closed method deep inside org.eclipse.jetty.websocket.common.events.annotated.CallableMethod class with the following message:
Parameter specified as non-null is null: method
webchat.WSHandler.closed, parameter reason
It is related to Kotlin's nullability features and all works fine when you declare your method using signature below:
fun closed(session: Session, statusCode: Int, reason: String?)

Related

Spring wrongfully tries to cast my sealed class into a Collection. Why?

I have a problem with Spring, kotlin, and sealed classes, and don't know where it comes from. It would seem Spring tries to cast my ErrorDto class into a collection, when it shouldn't have to cast it.
Context
I have a sealed class Response that wraps my responses.
sealed interface Response<T>
class ErrorResponse<T>(status: HttpStatus, message: String) : Response<T>,
ResponseEntity<ErrorDto>(ErrorDto(status.value(), message), status)
class SuccessResponse<T>(responseEntity: ResponseEntity<T>) : Response<T>, ResponseEntity<T>(responseEntity.body, responseEntity.headers, responseEntity.statusCode) {
constructor(body: T): this(ok(body))
}
class ErrorDto(val status: Int, #SerializedName("error") val message: String? = null)
All my requests return types are Response<AType>, where AType is a typical response type so that:
we have a ResponseEntity<AType> when the request succeeds,
and when the request encounters an error, it returns a ResponseEntity<ErrorDto>
The wrapper Response is here so that I can correctly type the responses to the REST requests.
Working example
This works correctly with custom types, and here is an example of request that works at runtime:
#GetMapping("/test1")
fun test1(): Response<MyCustomType> {
val response: Response<MyCustomType> = if (true) {
ErrorResponse(HttpStatus.CONFLICT, "test")
} else {
SuccessResponse(MyCustomType())
}
return response
}
The problem
And now, here's an example of what doesn't work at runtime (it compiles just fine):
#GetMapping("/test2")
fun test2(): Response<List<String>> {
val response: Response<List<String>> = if (true) {
ErrorResponse(HttpStatus.CONFLICT, "test")
} else {
SuccessResponse(listOf("toto"))
}
return response
}
The runtime error with this test2 is:
[org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: class ErrorDto cannot be cast to class java.util.Collection
Why?
It would seem that Spring tries to cast the type to a collection when the wrapped response type is a List (Response<List<String>> here), when it shouldn't do that.
Any idea where this problem comes from and why Spring tries to cast to a Collection when it shouldn't do that?
N.B.: As a workaround, I wrapped my List with MyCustomClass in order to go around the problem, but I would still like to understand the why.

Creating Per-Provider Loggers in Wire Dependency Injection

I'm using github.com/google/wire for dependency injection in an open source example project that I'm working on.
I have the following interfaces in a package named interfaces:
type LoginService interface {
Login(email, password) (*LoginResult, error)
}
type JWTService interface {
Generate(user *models.User) (*JWTGenerateResult, error)
Validate(tokenString string) (*JWTValidateResult, error)
}
type UserDao interface {
ByEmail(email string) (*models.User, error)
}
I have implementations that look like this:
type LoginServiceImpl struct {
jwt interfaces.JWTService
dao interfaces.UserDao
logger *zap.Logger
}
func NewLoginService(jwt interfaces.JWTService, dao interfaces.UserDao, \
logger *zap.Logger) *LoginServiceImpl {
return &LoginServiceImpl{jwt: jwt, dao: dao, logger: logger }
}
type JWTServiceImpl struct {
key [32]byte
logger *zap.Logger
}
func NewJWTService(key [32]byte, logger *zap.Logger) (*JWTServiceImpl, error) {
r := JWTServiceImpl {
key: key,
logger: logger,
}
if !r.safe() {
return nil, fmt.Errorf("unable to create JWT service, unsafe key: %s", err)
}
return &r, nil
}
type UserDaoImpl struct {
db: *gorm.DB
logger: *zap.Logger
}
func NewUserDao(db *gorm.DB, logger *zap.Logger) *UserDao {
return &UserDaoImpl{ db: db, logger: logger }
}
I'll exclude other factory functions and implementations here because they all look very similar. They may return an error or be infallible.
I have one other interesting factory for creating the database connection, which I'll just show the interface and not the implementation:
func Connect(config interfaces.MySQLConfig) (*gorm.DB, error) { /* ... */ }
Now, onto the problem. In my command-line entry-point, I'm creating a logger:
logger, err := zap.NewDevelopment()
For each of the factory methods above, I need to provide a logger and not the same logger instance, rather as if these methods were called as follows:
logger, err := zap.NewDevelopment()
// check err
db, err := database.Connect(config)
// check err
userDao := dao.NewUserDao(db, logger.Named("dao.user"))
jwtService, err := service.NewJWTService(jwtKey)
// check err
loginService := service.NewLoginService(jwtService, userDao, logger.Named("service.login"))
My wire.ProviderSet construction looks like this:
wire.NewSet(
wire.Bind(new(interfaces.LoginService), new(*service.LoginServiceImpl)),
wire.Bind(new(interfaces.JWTService), new(*service.JWTServiceImpl)),
wire.Bind(new(interfaces.UserDao), new(*dao.UserDaoImpl)),
service.NewLoginService,
service.NewJWTService,
dao.NewUserDao,
database.Connect,
)
I've read through the user guide, the tutorial, and best practices, and I can't seem to find a way to route a unique zap.Logger to each of these factory methods, and routing a random [32]byte for the JWT service.
Since my root logger is not created at compile time, and since each of these factory methods needs its own unique logger, how do I tell wire to bind these instances to the corresponding factory methods? I'm having a tough time seeing how to route custom instances of the same type to disparate factory methods.
In summary:
Wire seems to favor doing everything at compile-time, storing the dependency injection configuration in a static package-level variable. For most of my use-case, this is okay.
For the rest of my use-case, I need to create some instances manually before running the dependency injection and the ability to route various *zap.Logger instances to each service that needs it.
Essentially, I need to have wire do services.NewUserDao(Connect(mysqlConfig), logger.Named("dao.user"), but I don't know how to express this in wire and merge variables at runtime with wire's compile-time approach.
How do I do this in wire?
I had to change what I was doing somewhat, as is recommended in the documentation:
If you need to inject a common type like string, create a new string type to avoid conflicts with other providers. For example:
type MySQLConnectionString string
Adding Custom Types
The documentation is admittedly very terse, but what I ended up doing is creating a bunch of types:
type JWTKey [32]byte
type JWTServiceLogger *zap.Logger
type LoginServiceLogger *zap.Logger
type UserDaoLogger *zap.Logger
Updating Producer Functions
I updated my producer methods to accept these types, but did not have to update my structs:
// LoginServiceImpl implements interfaces.LoginService
var _ interfaces.LoginService = (*LoginServiceImpl)(nil)
type LoginServiceImpl struct {
dao interfaces.UserDao
jwt interfaces.JWTService
logger *zap.Logger
}
func NewLoginService(dao interfaces.UserDao, jwt interfaces.JWTService,
logger LoginServiceLogger) *LoginServiceImpl {
return &LoginServiceImpl {
dao: dao,
jwt: jwt,
logger: logger,
}
}
This above part made sense; giving distinct types meant that wire had less to figure out.
Creating an Injector
Next, I had to create the dummy injector and then use wire to generate the corresponding wire_gen.go. This was not easy and very unintuitive. When following the documentation, things kept breaking and giving me very unhelpful error messages.
I have a cmd/ package and my CLI entrypoint lives in cmd/serve/root.go, which is run as ./api serve from the command-line. I created my injector function in cmd/serve/injectors.go, note that // +build wireinject and the following newline are required to inform Go that this file is used for code generation and not code itself.
I ultimately arrived at the following code after much trial and error:
// +build wireinject
package serve
import /*...*/
func initializeLoginService(
config interfaces.MySQLConfig,
jwtKey service.JWTKey,
loginServiceLogger service.LoginServiceLogger,
jwtServiceLogger service.JWTServiceLogger,
userDaoLogger service.UserDaoLogger,
databaseLogger database.DatabaseLogger,
) (interfaces.LoginService, error) {
wire.Build(
// bind interfaces to implementations
wire.Bind(new(interfaces.LoginService), new(*service.LoginServiceImpl)),
wire.Bind(new(interfaces.JWTService), new(*service.JWTServiceImpl)),
wire.Bind(new(interfaces.UserDao), new(*dao.UserDao)),
// services
service.NewLoginService,
service.NewJWTService,
// daos
dao.NewUserDao,
// database
database.Connect,
)
return nil, nil
}
The wire.Bind calls inform wire which implementation to use for a given interface so it will know that service.NewLoginService which returns a *LoginServiceImpl should be used as the interfaces.LoginService.
The rest of the entities in the call to wire.Build are just factory functions.
Passing Values to an Injector
One of the the issues I ran into was that I was trying to pass values into wire.Build like the documentation describes:
Occasionally, it is useful to bind a basic value (usually nil) to a type. Instead of having injectors depend on a throwaway provider function, you can add a value expression to a provider set.
type Foo struct {
X int
}
func injectFoo() Foo {
wire.Build(wire.Value(Foo{X: 42}))
return Foo{}
}
...
It's important to note that the expression will be copied to the injector's package; references to variables will be evaluated during the injector package's initialization. Wire will emit an error if the expression calls any functions or receives from any channels.
This is what confused me; it sounded like you could only really use constant values when trying to run an injector, but there are two lines in the docs in the "injectors" section:
Like providers, injectors can be parameterized on inputs (which then get sent to providers) and can return errors. Arguments to wire.Build are the same as wire.NewSet: they form a provider set. This is the provider set that gets used during code generation for that injector.
These lines are accompanied by this code:
func initializeBaz(ctx context.Context) (foobarbaz.Baz, error) {
wire.Build(foobarbaz.MegaSet)
return foobarbaz.Baz{}, nil
}
This is what I missed and what caused me to lose a lot of time on this. context.Context doesn't seem to be passed anywhere in this code, and it's a common type so I just kind of shrugged it off and didn't learn from it.
I defined my injector function to take arguments for the JWT key, the MySQL config, and the logger types:
func initializeLoginService(
config interfaces.MySQLConfig,
jwtKey service.JWTKey,
loginServiceLogger service.LoginServiceLogger,
jwtServiceLogger service.JWTServiceLogger,
userDaoLogger service.UserDaoLogger,
databaseLogger database.DatabaseLogger,
) (interfaces.LoginService, error) {
// ...
return nil, nil
}
Then, I attempted to inject them into wire.Build:
wire.Build(
// ...
wire.Value(config),
wire.Value(jwtKey),
wire.Value(loginServiceLogger),
// ...
)
When I attempted to run wire, it complained that these types were defined twice. I was very confused by this behavior, but ultimately learned that wire automatically sends all function parameters into wire.Build.
Once again: wire automatically sends all injector function parameters into wire.Build.
This was not intuitive to me, but I learned the hard way that it's the way wire works.
Summary
wire does not provide a way for it to distinguish values of the same type within its dependency injection system. Thus, you need to wrap these simple types with type definitions to let wire know how to route them, so instead of [32]byte, type JWTKey [32]byte.
To inject live values into your wire.Build call, simply change your injector function signature to include those values in the function parameters and wire will automatically inject them into wire.Build.
Run cd pkg/my/package && wire to create wire_gen.go in that directory for your defined injectors. Once this is done, future calls to go generate will automatically update wire_gen.go as changes occur.
I have wire_gen.go files checked-in to my version control system (VCS) which is Git, which feels weird due to these being generated build artifacts, but this seems to be the way that this is typically done. It might be more advantageous to exclude wire_gen.go, but if you do this, you'll need to find every package which includes a file with a // +build wireinject header, run wire in that directory, and then go generate just to be sure.
Hopefully this clears up the way that wire works with actual values: make them type safe with type wrappers, and simply pass them to your injector function, and wire does the rest.

Spring WebFlux + Kotlin Response Handling

I'm having some trouble wrapping my head around a supposedly simple RESTful WS response handling scenario when using Spring WebFlux in combination with Kotlin coroutines. Suppose we have a simple WS method in our REST controller that is supposed to return a possibly huge number (millions) of response "things":
#GetMapping
suspend fun findAllThings(): Flow<Thing> {
//Reactive DB query, return a flow of things
}
This works as one would expect: the result is streamed to the client as long as a streaming media type (e.g. "application/x-ndjson") is used. In more complex service calls that also accounts for the possibility of errors/warnings I would like to return a response object of the following form:
class Response<T> {
val errors: Flow<String>
val things: Flow<T>
}
The idea here being that a response either is successful (returning an empty error Flow and a Flow of things), or failed (errors contained in the corresponding Flow while the things Flow being empty). In blocking programming this is a quite common response idiom. My question now is how can I adapt this idiom to the reactive approach in Kotlin/Spring WebFlux?
I know its possible to just return the Response as described (or Mono<Response> for Java users), but this somewhat defeats the purpose of being reactive as the entire Mono has to exist in memory at serialization time. Is there any way to solve this? The only possible solution I can think of right now is a custom Spring Encoder that is smart enough to stream both errors or things (whatever is present).
How about returning Success/Error per Thing?
class Result<T> private constructor(val result: T?, val error: String?) {
constructor(data: T) : this(data, null)
constructor(error: String) : this(null, error)
val isError = error != null
}
#GetMapping
suspend fun findAllThings(): Flow<Result<Thing>> {
//Reactive DB query, return a flow of things
}

Type assertions with interface embedding in Go

I have an interface and it is embedded into multiple structs that
form a decorator pattern.
Now I have added code to typecast Validator and APIService to the API interface. So that if I add and a function to the interface then I should be able to add it at Validator and APIService.
But this code seems to compile.
I should have got a compiler error as I have not implemented Get on Validator
If I remove Get from APIService I get an error which says I cant typecast to *APIService to API as get is not implemented.
package main
import "fmt"
type API interface {
Get()
}
var _ API = (*Validator)(nil)
var _ API = (*APIService)(nil)
type APIService struct {
id string
}
type Validator struct {
API
}
type APIRouter struct {
API
}
func(a *APIService) Get(){
fmt.Println("Calling Get api on APIService")
}
func NewAPIRouter() *APIRouter{
return &APIRouter{
API: &Validator{
API: &APIService{
},
},
}
}
func main() {
var api API = NewAPIRouter()
api.Get()
}
If I compile the above code:
./main
Calling Get api on APIService
But if I comment Get function on APIService i get the below error which is valid:
go build
# main
./main.go:9:5: cannot use (*APIService)(nil) (type *APIService) as type API in assignment:
*APIService does not implement API (missing Get method)
I should have got a compiler error before as well as I have not implemented Get on Validator
If I remove Get from APIService I get an error which says I cant typecast to *APIService to API as get is not implemented.
The type APIService is a struct with a method Get, so it implements API interface.
The type Validator is a struct with an embedded interface API. This means, a Validator instance has an embedded member that implements the API interface, and since it is embedded, Validator also implemented the API interface. However, note that you have to initialize Validator.API to an implementation first. Something like this should work:
v:=Validator{API:&APIService{}}
With this, v.Get() will call the embedded APIService.Get.

ConfigurationProperties loading list from YML

I'm trying to load Configuration from YML. I can load value and I can also load list if these are comma seperated values. But i can't load a typical YML List.
Configuration Class
#Component
#PropertySource("classpath:routing.yml")
#ConfigurationProperties
class RoutingProperties(){
var angular = listOf("nothing")
var value: String = ""
}
Working routing.yml
angular: /init, /home
value: Hello World
Not Working routing.yml
angular:
- init
- home
value: Hello World
Why can't i load the second version of yml / do I have a syntaxt error?
ENV: Kotlin, Spring 2.0.0.M3
As #flyx say, #PropetySource not worked with yaml files. But in spring you may override almost everything :)
PropertySource has additional parameter: factory. It's possible to create your own PropertySourceFactory base on DefaultPropertySourceFactory
open class YamlPropertyLoaderFactory : DefaultPropertySourceFactory() {
override fun createPropertySource(name: String?, resource: EncodedResource?): org.springframework.core.env.PropertySource<*> {
if (resource == null)
return super.createPropertySource(name, resource)
return YamlPropertySourceLoader().load(resource.resource.filename, resource.resource, null)
}
}
And when use this factory in propertysource annotation:
#PropertySource("classpath:/routing.yml", factory = YamlPropertyLoaderFactory::class)
Last that you need is to initialized variable angular with mutableList
Full code sample:
#Component
#PropertySource("classpath:/routing.yml", factory = YamlPropertyLoaderFactory::class)
#ConfigurationProperties
open class RoutingProperties {
var angular = mutableListOf("nothing")
var value: String = ""
override fun toString(): String {
return "RoutingProperties(angular=$angular, value='$value')"
}
}
open class YamlPropertyLoaderFactory : DefaultPropertySourceFactory() {
override fun createPropertySource(name: String?, resource: EncodedResource?): org.springframework.core.env.PropertySource<*> {
if (resource == null)
return super.createPropertySource(name, resource)
return YamlPropertySourceLoader().load(resource.resource.filename, resource.resource, null)
}
}
#SpringBootApplication
#EnableAutoConfiguration(exclude = arrayOf(DataSourceAutoConfiguration::class))
open class Application {
companion object {
#JvmStatic
fun main(args: Array<String>) {
val context = SpringApplication.run(Application::class.java, *args)
val bean = context.getBean(RoutingProperties::class.java)
println(bean)
}
}
}
Kinda old post, i know. But i am at the very same topic right now.
As of now, it seems that PropertySource does indeed work with yaml Files. Given the restriction that it only allows for primitive types (it seems) and it cant handle nested elements. I'm probably gonna dig a bit deeper and update my answer accordingly, but as of now, the accepted answer seems like a functioning workaround.
Well, according to the docs, your YAML file will be rewritten into a property file. The first YAML file becomes:
angular=/init, /home
value=Hello World
While the second one becomes:
angular[0]=init
angular[1]=home
value=Hello World
These are obviously two very different things and therefore behave differently.
Moreover, later in the docs, it is stated that YAML does not even work with #PropertySource:
24.6.4 YAML shortcomings
YAML files can’t be loaded via the #PropertySource annotation. So in the case that you need to load values that way, you need to use a properties file.
That makes me kind of wonder why the first case works for you at all.
The docs say this about the generated …[index] properties:
To bind to properties like that using the Spring DataBinder utilities (which is what #ConfigurationProperties does) you need to have a property in the target bean of type java.util.List (or Set) and you either need to provide a setter, or initialize it with a mutable value, e.g. this will bind to the properties above
So, let's have a look at Kotlin docs: listOf returns a new read-only list of given elements. So the list is not mutable as required by the docs, which I assume is why it doesn't work. Try using a mutable list (since I have never used Kotlin, I cannot give you working code). Also try to declare it as java.util.List if that's possible in Kotlin.

Resources