There's an API I have no influence on that has a JSON result object with a member that has 23 fields. The paradigm of case classes doesn't work, because there's a limit of 22. I've seen Slick and other libraries use HLists to resolve this. Is there a way to do this in Argonaut? If so, please give me sample piece of code to leverage. Thank you!
object BusinessResults{
implicit def BusinessResultsCodecJson: CodecJson[BusinessResults] =
casecodec23(BusinessResults.apply, BusinessResults.unapply)( /**... 23 fields ...**/)
}
I did not create an elegant solution for this. I just hand jammed a 23 piece for-comprehension to create the decoder.
Related
I have a situation where I have to have this case class Config[F[_]](pattern: String, format:F[String]), because sometimes the format should be present, and use it like Config[Id] and sometimes not and make it with Config[Option].
The question is, how is this coping with Play or Spray Json and what are some best practices to serialize / deseralize such a structure.
I use to use this trick few times before, but never forced to serialized until and I wonder how read and write methods should look like. Also, if there are any drawback or penalties, performance wise as well.
Any thoughts? Thanks, folks!
First of all, if derivation is not made bad, you would be able to make codecs for Config[List] and Config[Option].
In circe it should be like this:
implicit val configOptionCodec: Codec[Config[Option]] = deriveCodec
implicit val configListCodec: Codec[Config[List]] = deriveCodec
This won't give you much performance penalty, just boilerplate penalty. However you can write macro like #JsonCodecsFor(List, Option, Chain).
I have seen some of the other issues involving the infamous "22 fields/parameters" issue that is an inherent bug (feature?) of Scala V < 2.11. See here and here. However, as per this blog post, it appears that the 22 parameter limit in case class has been fixed; at least where the language is concerned.
I have a case class that I want to load an arbitrary (Read: > 22) number of values into which will later be read into a JSON object using the Play library.
It looks something like this:
object L {
import play.api.libs.json.Reads. _
import play.api.libs.functional.syntax._
implicit val responseRead: Reads[L] = (
MyField1.jsPath.Read[MyField1.t] and
MyField2.jsPath.Read[MyField2.t] and
...
MyField35.jsPath.Read[MyField35.t]
) (L.apply _)
}
case class L(myField1: MyField1.t, myField2: MyField2.t, ... myField35: MyField35.t)
The issue is that on compile, Scala complains that there are more than 22 parameters in the case class. (Specifically: on the last line of the object definition, when the compiler attempts to build, I get: "implementation restricts functions to 22 parameters".) I'm currently using Scala v2.11.6, so I think it's not a language issue. That makes me think that the Play library hasn't updated their implementation of Read.
If that's the case, then I guess the best bet is to group related fields into Tuples and pass the Tuples in through the JSON API?
As mentioned in the blog post you referenced, the 22-parameter limit is still in effect for functions in Scala 2.11 and later, so what you've encountered is a language issue. The function call in this case is:
L.apply _
Restructuring your model is one way to deal with this limit.
So the answer to this question is actually two parts:
1. Workaround
I'll call this the "workaround" because while it does "work" it usually addresses the symptom and not the problem.
My solution was to use shapeless to provide generic heterogeneous lists of arbitrary length. This solution is already widely discussed and available elsewhere. See, e.g., (1) [SO Post] How to get around the Scala case class limit of 22 fields?; (2) Blog post; (3) Yet another blog post.
2. Solution
As #jeffrey-chung mentions is to restructure the model to deal with this limit. As many in the industry have noted, having a function with more than 30 arguments is likely a sign that your function is doing too much or that the function should be refactored to ingest a smaller number of arguments. See, e.g., (1) Rule of 30 – When is a method, class or subsystem too big?; (2) Databrick's style guide.
See answer here
https://stackoverflow.com/a/57317220/1606452
It seems this handles it all nicely.
+22 field case class formatter and more for play-json
https://github.com/xdotai/play-json-extensions
Supports Scala 2.11.x, 2.12.x, and 2.13.x and play 2.3, 2.4, 2.5 and 2.7
And is referenced in the play-json issue as the preferred solution (but not yet merged)
I am new in scala programming, please consider the scenario...
.exec(http("request_7")
.post("/test/listing")
.headers(headers_12)
.formParam("abcId", "${abcID}")
.formParam("action_id", "100")
.formParam("controller", "/test/listing")
.check(jsonPath("$.data[*].xyzId").findAll.saveAs("xyzID"))
.check(jsonPath("$.data[*].abcNo").findAll.saveAs("ABCNo"))
.check(jsonPath("$.data[*].revId").findAll.saveAs("revID"))
.check(jsonPath("$.data[*].dTypeId").findAll.saveAs("dTypeID")))
In this request, I have to implement multiple check(s) to get the value. It is manual procedure.
Is there any method in scala to perform this scenario in single check? In other words,
I want to get these values in single json check. Is it possible???
So can anyone tell me what is the method to implement this scenario???
Your help would be much appreciated.
Thanks,
Praveen Mourya
One of the objects I've mocked must be converted into JSON but Spock does not seem to support the mocking of convertions. How can I choose which JSON will be returned?
Example of what I would like to achieve:
def "convert as JSON"()
{
when:
def product = Mock(Product)
println(product as JSON)
then:
1* (product as JSON) << (["message": "message"] as JSON)
}
This does not work however.
EDIT: Mocking the way the object is converted into JSON is useful, because what I want to achieve is to test a method of another class, that takes a product as argument and use it, calling "as JSON" on the product during it's execution. Since the products can be complex and have lots of dependencies and fields, I prefer to mock them. Spock then gives control over the output of the mocked products methods but it gets trickier when conversion is needed...
In your test, you're trying to reduce the complexity of an object (Product) to make your tests more simple. This is dangerous for two reasons:
Complicated tests are a code smell. They tell you "something is wrong". Trying to apply lots of deodorant on the smell will make things worse.
You're testing scenarios which can't happen in production.
The clean/better solution would be to refactor Product until it can be created easily and you don't need to mock it anymore. From what I know about your specific case, Product is a data object (like Integer, Long, BigDecimal). It just encodes state without much functionality of its own.
If that's true, it should be simple to create test cases without mocking. If you need mocking for data objects, then something is wrong with your code. Mocking is only needed for things like services - code which acts upon data objects and which has external dependencies which you need to cut for a test.
The second argument is that you're writing tests that pass but which don't tell a story. It's a complex form of having 10'000 tests that only contain assertTrue(true);. While it's a nice thing to have in terms of test count, it doesn't give you a single advantage over not having them at all.
Hi I need to turn the html of a partial into a json object (NOT TO BE RENDERED), but to be stored in a seperate format.
Something like this:
#json = (:partial => "/answers/likers" ,:type => :html)
Although the above obviously does not work, but hope you get the point, thanks!
Try render_to_string. It takes the same arguments as render, and just returns a string instead of outputting the data.
It looks like it's being deprecated but I can't find any new method that provides that same functionality for Rails 3. I tested it on a local Rails 3 setup, though, and it works for me. If anyone knows the "new" way to do this in Rails 3 please let me know, I'm interested now :)
Rails has a .to_json function. However, I never used this together with a partial ...