How to exchange DateTime between JPA with Spring and Retrofit on Android? - spring

How should I exchange DateTime objects between Spring and Retrofit?
At this moment I have timestamp in MySQL, Instant in JPA entities (because JPA Buddy uses Instant by default) and Spring produces YYYY-MM-DDTHH:mm:ss.sssZ string in JSON, but it looks like Retrofit is not able to deserialize it into Instant.
This is example of my Spring response:
[
{
"id": 1,
"code": "Abc",
"name": "Wiha PH3",
"description": null,
"created": "2022-10-10T12:00:00Z",
"modified": "2022-10-10T12:00:00Z",
}
]
At this moment I had to change my Retrofit DTO datetime fields from Instant to String because it was throwing exceptions about getting string instead of objects.
#Keep
data class InventoryItemDto(
var id: Int,
var code: String,
var name: String,
var description: String,
var created: String, // this is datetime!
var modified: String // this is datetime!
)
I have seen similar question here:
https://stackoverflow.com/a/34983454/1215291
but in this new project I can change data types in each layer, so maybe there is no need to mess around with deserializers or changing date time format in Spring?

Related

Kotlin OpenapiGenerator Any type generates into Map<String, JsonObject>

I'm struggling to find correct way to define Any object in Kotlin so that OpenApiGenerator would generate it as Object type.
I have a simple DTO object, payload is basically a map of object fields and values:
data class EventDto(
val payload: Map<String, Any>,
...other fields
)
Which gets converted to OpenAPI Spec and looks like this:
ommited code
...
"payload": {
"type": "object",
"additionalProperties": {
"type": "object"
}
},
But when I execute open-api-generator
this get's converted into Kotlin class looking like this:
#Serializable
public data class EventPayloadDto(
#SerialName(value = "payload")
val payload: kotlin.collections.Map<kotlin.String, kotlinx.serialization.json.JsonObject>? = null,
)
Which is not so nice convert into because each object value needs to be converted to JsonObject, is it possible to retain "Any" object when generating from OpenAPI docs or I must use Map<String, String>?
I tried using objectMapper.convert
objectMapper.convertValue(event, object : TypeReference<Map<String, JsonObject>>() {})
but since there are no serializers into JsonObject it had no effect and ended up in an error.

UUID field within Go Pact consumer test

I'm currently looking at adding Pact testing into my Go code, and i'm getting stuck on how to deal with field types of UUID.
I have the following struct, which I use to deserialise a response from an API to
import (
"github.com/google/uuid"
)
type Foo struct {
ID uuid.UUID `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
}
Now, when I try and write my consumer test, it looks something like this
pact.
AddInteraction().
Given("A result exists").
UponReceiving("A request to get all results").
WithRequest(dsl.Request{
Method: "get",
Path: dsl.String("/v1"),
}).
WillRespondWith(dsl.Response{
Status: 200,
Headers: dsl.MapMatcher{"Content-Type": dsl.String("application/json")},
Body: dsl.Match(&Foo{}),
})
The problem now, is the mocked response comes through as below, where it tries to put an array of bytes in the "id" field, I'm assuming since behind the scenes that is what the google/uuid library stores it as.
{
"id": [
1
],
"name": "string",
"description": "string"
}
Has anyone encountered this? And what would be the best way forward - the only solution I can see is changing my model to be a string, and then manually convert to a UUID within my code.
You currently can't use the Match function this way, as it recurses non primitive structures, albeit it should be possible to override this behaviour with struct tags. Could you please raise a feature request?
The simplest approach is to not use the Match method, and just manually express the contract details in the usual way.
The internal representation of uuid.UUID is type UUID [16]byte but json representation of UUID is string
var u uuid.UUID
u, _ = uuid.Parse("f47ac10b-58cc-0372-8567-0e02b2c3d479")
foo1 := Foo{u, "n", "d"}
res, _ := json.Marshal(foo1)
fmt.Println(string(res))
{
"id": "f47ac10b-58cc-0372-8567-0e02b2c3d479",
"name": "n",
"description": "d"
}
and then load marshaled []byte
var foo Foo
json.Unmarshal(res, &foo)

GraphQL: Nesting Reusable Interface Fragment within a Type Fragment

I'm new to GraphQL and Apollo Client.
I'm trying to write DRY queries as much possible and found that Fragments can be of great help.
Here is how my GraphQL schema would look like:
interface header { # Implemented by multiple types
uuid: ID!
created_at: DateTime
created_by: String
updated_at: DateTime
updated_by: String
}
type account implements header #withSubscription {
id: String! #id #search(by:[term])
name: String #search(by:[fulltext])
description: String #search(by:[fulltext])
...
}
on the client side, I'm trying to setup my operations.graphql as follows:
fragment headerData on header {
uuid
created_at
created_by
updated_at
updated_by
}
fragment accountNode on account {
...headerData
id
name
description
#.. rest of the fields
}
query getPaginatedAccounts(first: Int, offset: Int) {
queryaccount {
...accountNode
# .. rest of the fields
}
}
However, when I execute the query, the results set doesn't fetch any data from the accountNode fragment.
Is this correct way to nest the fragments?
I realize that if I change the accountNode fragment as follows, it works and gets me the data:
fragment accountNode on account {
... on header {
uuid
created_at
#..rest of header fields
}
id
name
description
#.. rest of the fields
}
But since header interface is implemented by multiple types, its not DRY to repeat those fields on every Type Fragment.
Thanks in advance.

passing json in json to spring controller

I am trying to pass json object to spring controller and I manage to do that, but value of one property is in json and I think that I have problem because of it. But there is no other way to pass that data. Code is below,
data class:
#Entity
data class Section(
#Id
#GeneratedValue
val id: Long = 0L,
val name: String = "",
var text: String,
#ManyToOne
var notebook: Notebook
)
Controller code:
#PutMapping("/sections/{id}")
fun updateSection(#RequestBody section: Section, #PathVariable id: Long): Section =
sectionRepository.findById(id).map {
it.text = section.text
it.notebook = section.notebook
sectionRepository.save(it)
}.orElseThrow { SectionNotFoundException(id) }
javascript sending post to api:
function updateApi(data) {
axios.put(MAIN_URL + 'sections/' + data.id, {
data
})
.then(showChangesSaved())
.catch(ShowErrorSync());
}
function saveSection() {
var data = JSON.parse(window.sessionStorage.getItem("curr-section"));
data.text = JSON.stringify(element.editor).toString();
updateApi(data);
}
I get error like this:
2020-11-18 15:06:24.052 WARN 16172 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Instantiation of [simple type, class org.dn.model.Section] value failed for JSON property text due to missing (therefore NULL) value for creator parameter text which is a non-nullable type; nested exception is com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException: Instantiation of [simple type, class org.dn.model.Section] value failed for JSON property text due to missing (therefore NULL) value for creator parameter text which is a non-nullable type
at [Source: (PushbackInputStream); line: 1, column: 375] (through reference chain: org.dn.model.Section["text"])]
so text in element.editor is JSON formatted string and I need to pass it as it is to controller. Is there any way to do that? I tried searching, but I can't find json in json help...
Whole project is available on github
What does your json looks like? If I check out your project and run the following two tests:
one with Section as an object as request body
one with Section as json
Both will succeed. So the problem might lie in your JSON:
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class HttpRequestTest {
#LocalServerPort
private val port = 0
#Autowired
private val restTemplate: TestRestTemplate? = null
#Test
fun sectionAsObject() {
val section = Section(0L, "2L", "text", Notebook(1L, "1", "2"))
assertThat(restTemplate!!.put("http://localhost:$port/sections/123", section
)).isNotNull
}
#Test
fun sectionAsJson() {
val sectionAsJson = """
{
"id": 0,
"name": "aName",
"text": "aText",
"noteBook": {
"id": 0,
"name": "aName",
"desc": "2"
}
}
""".trimIndent()
assertThat(restTemplate!!.put("http://localhost:$port/sections/123", sectionAsJson
)).isNotNull
}
}
BTW: it is not a pretty good habit to expose your database ids, which is considered to be a security risk as it exposes your database layer. Instead, you might want to use a functional unique key ;)

Graphql mutation error in aws amplify appsync

I am trying to insert/mutate a data using graphql to a dynamodb, see image below having error while inserting data. I am confused if the error exist while creating the schema or while mutating the data. The table was created using amplify
this is the schema script
type PersonalAttributes {
FirstName: String
LastName: String
MiddleName: String
Email: String
Highlights: String
}
type Configurations {
StudyTopic: String
SpokenLanguage: String
Gender: String
ReadbackSpeed: Float
}
type Chapter {
CTitle: String
Content: String
TermHighlights: [String]
}
type Book {
Title: String
Author: String
HighlightsChapter: [Chapter]
}
type Athena #model {
UserKey: ID
UserName: String!
PersonalInformation: [PersonalAttributes]
SysConfig: [Configurations]
Books: [Book]
}
I recommend including an id: ID! for your Athena model. Provide a valid ID whenever you create Athena objects.
The error indicates that no id was provided (Dynamo wanted a valid, non-null String, but it got null.)
The error results from the create mutation call, not from setup of the Dynamo table.

Resources