I'm using a Repository that extends a spring data JpaRepository and would like to let it extend another interface.
Previously, my db repository looked like this:
interface PublicTransportPricingZoneRepository : JpaRepository<PublicTransportPricingZone, Long> {
}
I have now created another interface TransitTicketRepo as defined below
interface TransitTicketRepo {
fun findPossibleTickets(geometry: Geometry): Collection<TransitTicket>
}
and now would like to implement the interface with a default method in PublicTransportPricingZoneRepository. I've tried to solve this by changing the code of my PublicTransportPricingZoneRepository to
interface PublicTransportPricingZoneRepository : JpaRepository<PublicTransportPricingZone, Long>, TransitTicketRepo {
fun findPossibleTickets(geometry: Geometry): Collection<TransitTicket> {
// do something
return emptyList()
}
}
but get the following error message when starting the application.
org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract java.util.Collection PublicTransportPricingZoneRepository.findPossibleTickets(Geometry); Reason: Failed to create query for method public abstract java.util.Collection...
I'm assuming the solution is to somehow tell spring data to stop auto-generating a query for findPossibleTickets but have been unable to find out how.
You can do it this way
In short.:
#Repository
// Your bean that will be glued together by spring
interface PublicTransportPricingZoneRepository extends JpaRepository<...>, PublicTransportPricingZoneCustomRepository {
// Other methods, but everything must be annotated with #Query or possible for spring to guess what it needs to do from its name (google derived methods)
}
interface PublicTransportPricingZoneCustomRepository {
// define custom methods
List<String> nameIsNotImportant();
}
#Service
// naming here is important - it must be names as interface + Impl, otherwise spring won't pick it up
// apart from that, it's a regular bean - you can Autowire, etc
class PublicTransportPricingZoneCustomRepositoryImpl implementats PublicTransportPricingZoneCustomRepository {
// Implement custom methods
#Overridden
public List<String> nameIsNotImportant() {
// impl
}
}
Related
I am working on a plugin type system where 3rd parties will register classes that will expose data. I don't know exactly what the data will look like but I will enumerate these plugin instances collect the data and I would like to serialise it. A simplified version.
interface DataProvider {
fun getDataThatIsSerializable() : ???
}
What can i set the return type to so that I know that I will be able to serialise it with kotlinx serialisation. I cannot see any common interface that is injected into the class and given thet kotlin doesn't support type classes its not clear how to achieve what I am trying to do?
I considered something like this:
interface DataProvider {
fun getDataThatIsSerializable() : Pair<Any,KSerializer<*>>
}
but i could not pass this into the Json.encodeAsString functions, the types do not match
Are there any other options I can consider?
kotlinx.serialization doesn't like serializing things unless you can tell it exactly what you're working with.
Would it make sense for the DataProvider to be responsible for serializing its own data? Something like:
interface DataProvider {
fun getDataThatIsSerializable() : Any
fun encodeAsJsonString(data: Any) : String
}
#Serializable
data class Foo(val value: Int)
class FooDataProvider : DataProvider {
override fun getDataThatIsSerializable() : Any {
return Foo(7)
}
override fun encodeAsJsonString(data: Any): String {
return Json.encodeToString(Foo.serializer(), data as Foo)
}
}
The Code A is from the project android/architecture-components-samples.
The author place the code of instance a class DefaultServiceLocator in the interface ServiceLocator.
In my mind , normally a interface should not include any implement code.
Is it a good idea to place the code of instance a class in a interface in Kotlin?
Code A
interface ServiceLocator {
companion object {
private val LOCK = Any()
private var instance: ServiceLocator? = null
fun instance(context: Context): ServiceLocator {
synchronized(LOCK) {
if (instance == null) {
instance = DefaultServiceLocator(
app = context.applicationContext as Application,
useInMemoryDb = false)
}
return instance!!
}
}
/**
* Allows tests to replace the default implementations.
*/
#VisibleForTesting
fun swap(locator: ServiceLocator) {
instance = locator
}
}
...
}
open class DefaultServiceLocator(val app: Application, val useInMemoryDb: Boolean) : ServiceLocator {
...
}
In my mind , normally a interface should not include any implement code.
Welcome back from hibernation ;) Yes, you could achieve the same with interface + abstract class but you can have default implementation also as part of the interface for some time now in many languages. Which way you go is up to you, but if you have only one abstract class implementing your interface then it is often handy to be able to merge this into one file for sake of ease of future maintenance.
As per kotlin interfaces documentation:
Interfaces in Kotlin can contain declarations of abstract methods, as well as method implementations. What makes them different from abstract classes is that interfaces cannot store state. They can have properties but these need to be abstract or to provide accessor implementations.
So... there's no problem in using method implementations on the interfaces. That feature might offer you extra power (if you like and need to use it).
Let me summerize what I am trying to achieve. Basically I want a way to have a set of interfaces which server an an api that external plugins use to interact with the engine.
Here is how I currently have things setup.
class Engine : ApiEngine {
override fun start() {
println("Starting Engine")
}
override fun stop() {
println("Stopping Engine.")
}
}
interface ApiEngine {
fun start()
fun stop()
}
This is cumbersome and I have seen some other solutions using ASM and injecting the interface dynamically into the "Engine" class. I have seen something like this in another source but never could fully figure out how to do.
#Implements("ApiEngine")
class Engine {
#Export("start")
fun start() {
println("Starting Engine")
}
#Export("stop")
fun stop() {
println("Stopping Engine.")
}
}
interface ApiEngine {
#Import("start")
fun start()
#Import("stop")
fun stop()
}
My question is, in ByteBuddy, is it possible to effively make Engine implement ApiEngine so that it an instance of Engine() can be cast to ApiEngine for API usage?
This is very much possible. You can for example integrate Byte Buddy as a build tool where you generate interfaces upon discovery. Simply implement the Plugin interface and match types based on your annotation being present.
As a next step, you would need to instrument those types to implement an additional interface using the DynamicType.Builder DSL that Byte Buddy provides you. If your methods always match their signature, there is nothing more to be done since Byte Buddy automatically detects those overrides. If the method signatures can vary, you would need to implement the interface methods using MethodCall to implement a delegation to the actual implementation.
Lets say I have two interfaces like:
interface LetterClassifier
interface NumberClassifier
Then these interfaces would be applied to this class:
class Classifier() : LetterClassifier, NumberClassifier
Now, I want to provide these instances only as LetterClassifier and NumberClassifier and not as Classifier in Koin.
The way I think of doing this is by doing:
module {
val classifier = Classifier()
single<NumberClassifier> { classifier }
single<LetterClassifier> { classifier }
}
But I don't think this is the right way. Can someone guide me?
You could bind types to your definition like it is described on official article:
single { Classifier() } binds arrayOf(LetterClassifier::class, NumberClassifier::class)
If you want to exclude Classifier type at all you could do something like:
single<LetterClassifier> { Classifier() } bind NumberClassifier::class
The way you're doing it is in fact the right way! Here's another example from the Koin docs, doing the same thing:
class DataRepository()
interface Presenter
class MyPresenter(val repository : Repository) : Presenter
val myModule = module {
// Define a singleton for type DataRepository
single { DataRepository() }
// Define a factory (create a new instance each time) for type Presenter (infered parameter in <>)
// Resolve constructor dependency with get()
factory<Presenter> { MyPresenter(get()) }
}
One small thing to note when doing this: your approach immediately creates an instance at the time the module declaration is being processed, while placing the constructor calls in the single lambdas would create instances when needed:
single<NumberClassifier> { Classifier() }
single<LetterClassifier> { Classifier() }
Although this would create a separate single instance for both of the interfaces.
You can have a function or a Singleton to provide instance,
single<NumberClassifier> { Singleton.createClassifier() }
single<LetterClassifier> { Singleton.createClassifier() }
i develop a micro services application with Kotlin Webflux (Reactor3), Eureka, Zuul and Feign. Except that I always have an error when I make a call to an API via my micro service Feign. It looks like he can not deserialize the data. Could you please tell me if Feign is compatible with Flux and Monno?
thank you
{
"timestamp": "2019-05-29T07:39:43.998+0000",
"path": "/hobbies/",
"status": 500,
"error": "Internal Server Error",
"message": "Type definition error: [simple type, class reactor.core.publisher.Flux]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of reactor.core.publisher.Flux (no Creators, like default construct, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information\n at [Source: (PushbackInputStream); line: 1, column: 1]"
}
Feign doesn't provide support for Mono/Flux deserialiazation. There exists alternative feign library who fully support it: feign-reactive.
Note though, this is a rewrite of feign which fully use reactive code, differ from OpenFeign's Feign core.
Here's a snippet on how to use it, alongside with normal Feign, taken from the sample app.
#SpringBootApplication(exclude = ReactiveLoadBalancerAutoConfiguration.class)
#RestController
#EnableReactiveFeignClients
#EnableFeignClients
public class FeignApplication {
#Autowired
private GreetingReactive reactiveFeignClient;
#Autowired
private Greeting feignClient;
public static void main(String[] args) {
SpringApplication.run(FeignApplication.class, args);
}
#GetMapping("/greetingReactive")
public Mono<String> greetingReactive() {
return reactiveFeignClient.greeting().map(s -> "reactive feign! : " + s);
}
#GetMapping("/greeting")
public String greeting() {
return "feign! : " + feignClient.greeting();
}
}
In addition to Adhika Setya Pramudita response, I would like to mention that in order to return Mono in controller, you must use Spring WebFlux instead of Spring MVC
I was not able to make #Adhika Setya Pramudita solution working and gut tells me that it cannot even run due to mixing #EnableReactiveFeignClients and
#EnableFeignClients which are require corresponding #EnableWebFlux or #EnableWebMvc and thus defining both may compile but will fail in runtime.
Since op did not mention target language I'm feeling like to share Kotlin setup that works in my case:
build.gradle.kts
implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation("com.playtika.reactivefeign:feign-reactor-core:2.0.22")
implementation("com.playtika.reactivefeign:feign-reactor-spring-configuration:2.0.22")
implementation("com.playtika.reactivefeign:feign-reactor-webclient:2.0.22")
Config.kt
#Configuration
#EnableWebFlux
#EnableReactiveFeignClients
class Config {
}
MyEntity.kt
class MyEntity #JsonCreator constructor(
#param:JsonProperty("my_value") val my_value: String
)
MyFeignClient.kt
#Component
#ReactiveFeignClient(
url = "\${package.service.my-service-url}",
name = "client"
)
interface MyFeignClient {
#GetMapping(value = ["/my/url?my_param={my_value}"], consumes = ["application/json"])
fun getValues(
#PathVariable(name = "my_value") myValue: String?,
): Mono<MyEntity?>?
}
Then here goes code in some service class:
val myClient: MyFeignClient = WebReactiveFeign.builder<MyFeignClient>()
.contract(ReactiveContract(SpringMvcContract()))
.target(MyFeignClient::class.java, "http://example.com")
// feel free to add .block() to get unpacked value or just chain your logic further
val response = myClient.getValues(param)