feature: #2542 Dynamic proxy pattern (#2814)

* #2542 First commit

* #2542 Fixing comments

* #2542 Refactoring code

* #2542 Update Readme

* #2542 Add mockito dependencies

* #2542 Add unit test

* #2542 Fixes for testing

* #2542 Fixing typos

* #2542 Fixing SonarLint issues

* #2542 Fixing code review

---------

Co-authored-by: Sashir Estela <sashirestela@yahoo.com>
Co-authored-by: Ilkka Seppälä <iluwatar@users.noreply.github.com>
This commit is contained in:
Sashir Estela
2024-03-23 12:34:32 +02:00
committed by GitHub
co-authored by Sashir Estela Ilkka Seppälä
parent 4b704c807f
commit f65bb820d8
22 changed files with 1542 additions and 0 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

@@ -0,0 +1,35 @@
@startuml
class A as "App" {
}
interface I as "MyInterface" {
someMethod(args)
otherMethods(args)
}
class P as "Proxy" <<Built-In>> {
{static} DynamicProxy newProxyInstance(\n classLoader,\n interfaces,\n invocationHandler\n)
}
class D as "DynamicProxy" {
someMethod(args)
otherMethods(args)
}
class H as "InvocationHandler" {
invoke(proxy, method, args)
}
class X as "AuxiliarProcessor" {
process(method, args)
}
A -r-> D
I <|.. D : implements
D -r-> H : delegate
H -r-> X : (optional)
@enduml
Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

@@ -0,0 +1,63 @@
@startuml
participant App as A
participant Proxy as P <<Built-In>>
participant DynamicProxy as D <<MyInterface>>
participant InvocationHandler as H
participant AuxiliarProcessor as R
== Create Dynamic Proxy ==
create H
A -> H : new(args)
activate H
create R
H -> R : new(args)
activate R
R --> H : processor
deactivate R
H --> A : invocationHandler
deactivate H
|||
A -> P : newProxyInstance(\n classLoader,\n new Class<?>[]{MyInterface.class},\n invocationHandler\n)
activate P
create D
P -> D : new
activate D
D --> P : dynamicProxy
deactivate D
P --> A : dynamicProxy
deactivate P
== Call Interface's Method ==
A -> D : someMethod(args)
activate D
D -> H : invoke(proxy, method, args)
activate H
H -> R : process(method, args)
activate R
R -> R : parse method's\nmetadata
R -> R : execute some\nprocessing
R --> H : response
deactivate R
H --> D : response
deactivate H
D --> A : response
deactivate D
@enduml
+96
View File
@@ -0,0 +1,96 @@
@startuml
package com.iluwatar.dynamicproxy.tinyrestclient.annotation {
interface Body {
}
interface Delete {
+ value() : String {abstract}
}
interface Get {
+ value() : String {abstract}
}
interface HttpMethod {
}
interface Path {
+ value() : String {abstract}
}
interface Post {
+ value() : String {abstract}
}
interface Put {
+ value() : String {abstract}
}
}
package com.iluwatar.dynamicproxy.tinyrestclient {
class JsonUtil {
- objectMapper : ObjectMapper {static}
- JsonUtil()
+ jsonToList(json : String, clazz : Class<T>) : List<T> {static}
+ jsonToObject(json : String, clazz : Class<T>) : T {static}
+ objectToJson(object : T) : String {static}
}
class TinyRestClient {
- baseUrl : String
+ TinyRestClient(baseUrl : String)
- annotationValue(annotation : Annotation) : String
- buildBodyPublisher(method : Method, args : Object[]) : BodyPublisher
- buildUrl(method : Method, args : Object[], httpMethodAnnotation : Annotation) : String
- getAnnotationOf(annotations : Annotation[], clazz : Class<?>) : Annotation
- getHttpMethodAnnotation(annotations : Annotation[]) : Annotation
- getResponse(method : Method, httpResponse : HttpResponse<String>) : Object
+ send(method : Method, args : Object[]) : Object
}
}
package com.iluwatar.dynamicproxy {
class Album {
- id : Integer
- title : String
- userId : Integer
+ Album()
+ Album(id : Integer, title : String, userId : Integer)
+ builder() : AlbumBuilder {static}
# canEqual(other : Object) : boolean
+ equals(o : Object) : boolean
+ getId() : Integer
+ getTitle() : String
+ getUserId() : Integer
+ hashCode() : int
+ setId(id : Integer)
+ setTitle(title : String)
+ setUserId(userId : Integer)
+ toString() : String
}
class AlbumBuilder {
- id : Integer
- title : String
- userId : Integer
~ AlbumBuilder()
+ build() : Album
+ id(id : Integer) : AlbumBuilder
+ title(title : String) : AlbumBuilder
+ toString() : String
+ userId(userId : Integer) : AlbumBuilder
}
class AlbumInvocationHandler {
- restClient : TinyRestClient
+ AlbumInvocationHandler(baseUrl : String)
+ invoke(proxy : Object, method : Method, args : Object[]) : Object
}
interface AlbumService {
+ createAlbum(Album) : Album {abstract}
+ deleteAlbum(Integer) : Album {abstract}
+ readAlbum(Integer) : Album {abstract}
+ readAlbums() : List<Album> {abstract}
+ updateAlbum(Integer, Album) : Album {abstract}
}
class App {
~ REST_API_URL : String {static}
- albumServiceProxy : AlbumService
+ App()
+ callMethods()
+ createDynamicProxy()
+ main(args : String[]) {static}
}
}
AlbumInvocationHandler --> "-restClient" TinyRestClient
App --> "-albumServiceProxy" AlbumService
@enduml