mongo-scala-driver: Getting Results - mongodb-query

I have the following document in Mongodb:
{ "index_column" : "site_id", "mapped_column":"site_name"}
I'm using the mongo-scala-driver from my scala code to query the server. How do I get the mapped_column to a scala String variable? I tried with the following code:
val result = mongocollection.find(equal("index_column", data)).first()
It returns a org.mongodb.scala.ObservableImplicits$BoxedObservable#207c9b87
Is it possible to convert the Observable to an Iterator? I just need the mapped_column value in a scala String variable.

Scala driver is completely asynchronous, so you can subscribe for the result. The simplest way is to use foreach:
val result = mongocollection.find(equal("index_column", data)).first()
result.foreach { value => ... }
Another option is to convert Observable to Future:
Await.result(result.toFuture(), 3 seconds)

I resolved this issue by switching the driver to mongodb casbah and it can be done with the following code:
val result = mongocollection.find(MongoDBObject("index_column"-> "site_id")).one()
println(result.get("mapped_column"))

Related

Extracting Nested POJO Object with Rest-Assured

I'm writing some tests using rest-assured and its Kotlin extensions to test some simple Spring MVC endpoints. I'm trying to understand how to extract values.
One endpoint returns a BookDetailsView POJO, the other returns a Page<BookDetailsView> (where Page is an interface provided by Spring for doing paging).
BookDetailsView is a really simple Kotlin data class with a single field:
data class BookDetailsView(val id: UUID)
For the single object endpoint, I have:
#Test
fun `single object`() {
val details = BookDetailsView(UUID.randomUUID())
whenever(bookDetailsService.getBookDetails(details.id)).thenReturn(details)
val result: BookDetailsView = Given {
mockMvc(mockMvc)
} When {
get("/book_details/${details.id}")
} Then {
statusCode(HttpStatus.SC_OK)
} Extract {
`as`(BookDetailsView::class.java)
}
assertEquals(details.id, result.id)
}
This works as expected, but trying to apply the same technique for the Page<BookDetailsView> runs afoul of all sorts of parsing challenges since Page is an interface, and even trying to use PageImpl isn't entirely straightforward. In the end, I don't even really care about the Page object, I just care about the nested list of POJOs inside it.
I've tried various permutations like the code below to just grab the bit I care about:
#Test
fun `extract nested`() {
val page = PageImpl(listOf(
BookDetailsView(UUID.randomUUID())
))
whenever(bookDetailsService.getBookDetailsPaged(any())).thenReturn(page)
val response = Given {
mockMvc(mockMvc)
} When {
get("/book_details")
} Then {
statusCode(HttpStatus.SC_OK)
body("content.size()", `is`(1))
body("content[0].id", equalTo(page.first().id.toString()))
} Extract {
path<List<BookDetailsView>>("content")
}
println(response[0].javaClass)
}
The final println spits out class java.util.LinkedHashMap. If instead I try to actually use the object, I get class java.util.LinkedHashMap cannot be cast to class BookDetailsView. There are lots of questions and answers related to this, and I understand it's ultimately an issue of the underlying JSON parser not knowing what to do, but I'm not clear on:
Why does the "simple" case parse without issue?
Shouldn't the type param passed to the path() function tell it what type to use?
What needs configuring to make the second case work, OR
Is there some other approach for grabbing a nested object that would make more sense?
Digging a bit into the code, it appears that the two cases may actually be using different json parsers/configurations (the former seems to stick to rest-assured JSON parsing, while the latter ends up in JsonPath's?)
I don't know kotlin but here is the thing:
path() doesn't know the Element in your List, so it'll be LinkedHashMap by default instead of BookDetailsView.class
to overcome it, you can provide TypeReference for this.
java example
List<BookDetailsView> response = ....then()
.extract().jsonPath()
.getObject("content", new TypeRef<List<BookDetailsView>>() {});
kotlin example
#Test
fun `extract nested`() {
var response = RestAssured.given().get("http://localhost:8000/req1")
.then()
.extract()
.jsonPath()
.getObject("content", object : TypeRef<List<BookDetailsView?>?>() {});
println(response)
//[{id=1}, {id=2}]
}

Using ranges for lists or arrays in Kotlin

I have tried and I failed. Which cases that "ranges" used for?
var list = listOf(1,2,3,4,5)
It's worked well. But following code didn't work as I wanted. Why?
var list = listOf(1 .. 5)
Runnable program is : https://pl.kotl.in/c5256MZEC.
That syntax creates a list of ranges (List<IntRange>) with a single range in it. You can convert a range (or any Iterable) to a List with toList():
(1..5).toList()
You can also iterate through it without having to convert it to a list
var list2 = 1..5
list2.forEach {
println(it)
}
Another option (same as #Tenfour04 response but more readable) is to use the rangeTo operator and convert it to a list with the same extension function toList:
val list = 1.rangeTo(5).toList()

Reactive Spring Many Query Parameters

Tell me how to work with ServerRequest. If I need to get N parameters.
I find simple example with 1 parameter.
Reactive Spring Query Parameters
request
.getQueryParam("type")
.map(type -> service.getAddressByType(type))
.orElseGet(() -> service.getAllAddresses());
You can use getQueryParams to get N parameters as a map.
getQueryParams() returns MultiValueMap, so you can handle query params as a map.
Let me make small example like your code block.
val queryParamsMap = request.queryParams()
queryParamsMap["type"]?.let { type -> service.getAddressByType(type) } ?: let { service.getAllAddresses() }

Micronaut declarative client with base url per environment

I'd like to be able to use Micronaut's declarative client to hit an a different endpoint based on whether I'm in a local development environment vs a production environment.
I'm setting my client's base uri in application.dev.yml:
myserviceclient:
baseUri: http://localhost:1080/endpoint
Reading the docs from Micronaut, they have the developer jumping through quite a few hoops to get a dynamic value piped into the actual client. They're actually quite confusing. So I've created a configuration like this:
#ConfigurationProperties(PREFIX)
class MyServiceClientConfig {
companion object {
const val PREFIX = "myserviceclient"
const val BASE_URL = "http://localhost:1080/endpoint"
}
var baseUri: String? = null
fun toMap(): MutableMap<String, Any> {
val m = HashMap<String, Any>()
if (baseUri != null) {
m["baseUri"] = baseUri!!
}
return m
}
}
But as you can see, that's not actually reading any values from application.yml, it's simply setting a const value as a static on the class. I'd like that BASE_URL value to be dynamic based on which environment I'm in.
To use this class, I've created a declarative client like this:
#Client(MyServiceClientConfig.BASE_URL)
interface MyServiceClient {
#Post("/user/kfc")
#Produces("application/json")
fun sendUserKfc(transactionDto: TransactionDto)
}
The docs show an example where they're interpolating values from the config map that's built like this:
#Get("/api/\${bintray.apiversion}/repos/\${bintray.organization}/\${bintray.repository}/packages")
But how would I make this work in the #Client() annotation?
Nowhere in that example do they show how bintray is getting defined/injected/etc. This appears to be the same syntax that's used with the #Value() annotation. I've tried using that as well, but every value I try to use ends up being null.
This is very frustrating, but I'm sure I'm missing a key piece that will make this all work.
I'm setting my client's base uri in application.dev.yml
You probably want application-dev.yml.
But how would I make this work in the #Client() annotation?
You can put a config key in the #Client value using something like #Client("${myserviceclient.baseUri}").
If you want the url somewhere in your code use this:
#Value("${micronaut.http.services.occupancy.urls}")
private String occupancyUrl;

Trying to use java sdk and return Json and having issue with gson code

I am making a call to splunk and then I am trying to use the ResultsReaderJson class to get my results.
InputStream results = jobSavedSearch.getResults();
ResultsReaderJson resultsReader = new ResultsReaderJson(results);
And I keep getting this error.
com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 6
I have no access to the JsonReader from this class. Does anybody have any ideas of what I can do to get around this?
You have not asked for the results stream to return you JSON. The default is XML. To fix this you could use:
Args outputArgs = new Args();
outputArgs.put("output_mode","json");
InputStream results = jobSavedSearch.getResults(outputArgs);
In Splunk 1.3.0 API you can do:
JobExportArgs jobargs = new JobExportArgs();
jobargs.setOutputMode(JobExportArgs.OutputMode.JSON);
InputStream exportSearch = jobSavedSearch.getResults(jobargs);
MultiResultsReaderJson multiResultsReader = new MultiResultsReaderJson(exportSearch);