Using JSON templates in Play 2.0 - json

I'm getting this error:
Compilation error [package views.json.Runs does not exist]
when it clearly does exist. I can't figure out what I could be doing wrong.
the action in the Runs controller:
#BodyParser.Of(play.mvc.BodyParser.Json.class)
public static Result view(Long task_id, Long run_id) {
Run run = Run.find.byId(run_id);
return ok(views.json.Runs.view.render(run));
}
app/views/Runs/view.scala.json:
#(run: Run)
{
"started": "#run.started",
"completed": "#run.completed"
}
I've gotten a few html templates working, but this is the first JSON template I've tried with 2.0. I'm not sure what else to try since it's already about as basic as possible. Anyone have any ideas?
Update: I've gotten several suggestions for workarounds, but I'm still interested in knowing how to get the templates working, if only to better understand the changes to 2.0.

Only html, xml and txt appear to be supported by default. For other file extensions and formats, you'd have to register additional "templateTypes" in $PLAY_HOME/framework/src/sbt-plugin/src/main/scala/PlaySettings.scala (see also: SBT Settings, near the bottom).
It may be helpful to look at the standard template types definitions which are in $PLAY_HOME/framework/src/play/src/main/scala/play/api/templates/Templates.scala.
You could also cheat and serve your json from a txt file, but do response().setContentType("application/json") before calling the render method.

For Json, why don't you directly produce a Json string using the Json helper:
public static Result view(Long task_id, Long run_id) {
Run run = Run.find.byId(run_id);
return ok(play.libs.Json.toJson(run));
}

I recommend following the documentation and let the Json library serialize your data instead of writing the Json text on your own: See Serving Json Response.

I still don't understand, why does people want to render theirs JSON with views.
Note: this is the same way as #nico_ekito showed before and I agree with him totally , below code just demonstrates how to select part of the object for JSON
public static Result view(Long task_id, Long run_id){
Run run = Run.find.byId(run_id);
ObjectNode result = Json.newObject();
result.put("started", run.started);
result.put("completed", run.completed);
return ok(Json.toJson(result));
}

Related

Unexpected behaviour from Gson

I developed a small application that stores data coming from a device: I chose to store data in JSON format, and the serialization/deserialization of the data works just fine, even if it involves some custom types created by me...but only I work in the IDE (Eclipse, for that matter).
When I export a runnable JAR file though, the deserialization of the data encounters some kind of problem, because the software always throws this exception:
Caused by: java.lang.UnsupportedOperationException: Cannot allocate class LocalDateTime
at com.google.gson.internal.UnsafeAllocator$4.newInstance(UnsafeAllocator.java:104)
at com.google.gson.internal.ConstructorConstructor$14.construct(ConstructorConstructor.java:225)
... 88 common frames omitted
I thought I'd encounter problems with custom types, not a built-in one. At this point, I discovered two things:
if I use a full JRE 9 to run the JAR file, the exception is not thrown: I double checked the modules included in the custom JRE I created with Jlink.exe, and everything is included correctly. I still want to use a smaller JRE, so I did not investigate further yet (I guess this explains why in the IDE it works perfectly)
I added a custom deserializer to the Gson object (see below), with which I simply manually converted the JSON string into a valid data, and that avoided the exception on the LocalDateTime class...but the exception reappeared simply on another class, this time a custom-made one.
At this point, I guess I can simply add a deserializer for each data type that causes problem, but I'm wondering why the issue won't happen with a full JRE, and why a smaller JRE causes this, even if all the modules required are included. Maybe it's worth mentioning also that I added no custom serializer to the Gson object that saves the data, it is all serialized as per Gson default.
LocalDateTime deserializer:
#Override
public LocalDateTime deserialize(JsonElement json, java.lang.reflect.Type type,
JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
JsonObject joDate = json.getAsJsonObject().get("date").getAsJsonObject();
JsonObject joTime = json.getAsJsonObject().get("time").getAsJsonObject();
//JSON example: {"date":{"year":2019,"month":1,"day":9},"time":{"hour":6,"minute":14,"second":1,"nano":0}
return LocalDateTime.of(joDate.get("year").getAsInt(),
joDate.get("month").getAsInt(),
joDate.get("day").getAsInt(),
joTime.get("hour").getAsInt(),
joTime.get("minute").getAsInt(),
joTime.get("second").getAsInt(),
joTime.get("nano").getAsInt());
}
}
Jdeps.deps modules list:
com.google.gson
java.base
javafx.base
javafx.controls
javafx.fxml
javafx.graphics
org.slf4j
After the answer I received, I opened an issue here.
TL;DR
You need a runtime image (e.g. full JDK or something built with jlink) that includes the module jdk.unsupported.
Full Answer
GSON wants to create instances of classes it deserializes without calling any constructors (so nothing gets initialized without GSON saying so). This can't normally be done, but sun.misc.Unsafe offers a way to do this with the method allocateInstance. To that end, GSON needs an instance of sun.misc.Unsafe. The topmost frame in the call stack is from UnsafeAllocator, which uses common trickery to get Unsafe.
The problem is, sun.misc.Unsafe is in module jdk.unsupported, which is present in a full JDK but you won't usually find in runtime images.
When creating your runtime image with jlink, make sure to include the option --add-modules jdk.unsupported and you should be good to go.
Arguably, GSON should declare an optional dependency on jdk.unsupported with requires static.
I have faced the same issue when packing compose a desktop application.
update build.gradle file, add an unsupported module.
compose.desktop {
application {
mainClass = "MainKt"
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "admin"
packageVersion = "1.0.0"
modules("java.sql")
modules("jdk.unsupported")
}
}
}

Cant get json4s data extraction to work

Im working on a project that has scala backend and scalatra as a servlet. For now, the backend is running inside a Vagrant box, and sbt is used to build the program.
My problem is that I need to handle incoming Json-formatted data, but I cant extract it properly - though I'm able to send Json data. First I played around with Scalas own Json parser, but realized that it's deprecated, so I had to find external library. After that I came up with json4s.
In my app I have the following endpoint listening for incoming post requests
post("/my/endpoint") {
// run the code in here
}
And that works just fine. I can put trivial println inside the brackets and it displays in the sbt shell after the endpoint has been called.
After that I defined a case class to be used to extract the data
case class Person(name : String) {
override def toString() = s"My name is $name"
}
And lastly I did the following code inside my endpoint function
post("/my/endpoint") {
val json = parse(request.body)
val person = json.extract[Person]
println(person)
}
So right now when calling the println it should print whatever the toString method of Person class returns, but it prints nothing.
Lets take a step back and modify the code so that we have the following
post("/my/endpoint") {
val json = parse(request.body)
println(json)
}
This piece of code prints the following into sbt shell
JObject(List((name,JString(joe))))
So we can see that the parse-function is actually doing something and data is being received.
But, if we add
person = json.extract[Person]
after println(json), the endpoint stops functioning. Why I think it's weird, is because it's not a compiling error, so everything before that line should work properly? Also it doesn't cause the program to crash on runtime, nor does it give any errors, warnings, etc. Every other endpoint and functions works still properly.
Also, I did try the example in json4s.org under the section 'Extracting values'.
I copied the code from word to word, but that did not work either.
Also FYI, my versions are SBT, 1.1.6, Scala 2.12.6, Scalatra 2.6.3, json4s 3.5.2 and Vagrant is using Xenial 16.04 as its basebox.
pls help mi

How to Publish JSON Object on ActiveMQ

I am trying to publish JSON Message(Object) on to the ActiveMQ queue/topic.
currently i am converting JSON object into String then publishing it.
But i don't want to convert it into String.I don't want to convert it into String instead of that i want to send as it is JSON Object as a Message.
Below is my code
public void sendMessage(final JSONObject msg) {
logger.info("Producer sends---> " + msg);
jmsTemplate.send(destination, new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
String s = msg.toString();
return session.createTextMessage(s);
// createTextMessage(msg);
}
});
}
Using text on the queue is best practice since you will be able to debug a lot easier as well as not being restricted to the exactly same language/framework or even version of the libraries on the applications on both sides of the queue.
If you really want that hard coupling (i.e. when you are using the queue inside a single application and don't need to inspect messages manually on the queues) you can do it:
instead of return session.createTextMessage(s); do return session.createObjectMessage(msg);
One more thing: Be aware that using JMS ObjectMessage may cause security issues if you don't have 100% control of the code posting messages. Therefore this is not allowed in default ActiveMQ settings. You need to enable this in both client and server settings. For reference, see this page: http://activemq.apache.org/objectmessage.html

How does `traceur-compiler` work to convert ES-next to ES-present

I googled to find any existing ES-6 to ES-5 transpiler. There I found traceur-compiler. I just tried it by embedding on a page and found it working fine.
Then I was curious to understand that how the traceur-compiler actually work under the hood. Then I went to understand the source code of the library which was taking me quite long time to understand the internal implementation of the library.
I believe for understanding the working of traceur-compiler if I get some tool or some mechanism which shows the equivalent ES-5 output for some of the sample input of ES-6 script. It would be a lot easier for me to understand the working.
For example let's say following is sample ES-6 code
class Greeter {
constructor(message) {
this.message = message;
}
greet() {
console.info(this.message); // 'Hello, world!'
}
};
var greeter = new Greeter('Hello, world!');
greeter.greet();
I would like to know the ES-5 equivalent of the above code.
Any idea if there is debugging mode of traceur-compiler or some other tool facilitating me the same.
Just invoke the compiler on the command line. Here are instructions:
$ ./traceur --out out/greeter.js --script greeter.js
You can also use their online transcoding demo to get a quick of what ES5 gets generated. I made a simple class and got to see the generated JS here:
http://google.github.io/traceur-compiler/demo/repl.html#class%20Foo%20%7B%0A%20%20constructor()%20%7B%0A%20%20%20%20this.bar%20%3D%20%22yay%22%3B%0A%20%20%7D%0A%7D%0A%0A%0A%20%20
(Try http://google.github.io/traceur-compiler/demo/repl.html if the above link stops working).

How do I unit test a Grails service that uses a converter?

I have a Grails service that sends out e-mails using a 3rd-party service by doing a HTTP call:
class EmailService {
def sendEmail(values) {
def valueJson = values as JSON
... // does HTTP call to 3rd party service
}
}
I've written a unit test to test this service (because an integration test spins up Hibernate and the entire domain framework, which I don't need):
#TestFor(EmailService)
class EmailServiceTests {
void testEmailServiceWorks() {
def values = [test: 'test', test2: 'test2']
service.sendEmail(values)
}
}
However, when I execute this unit test, it fails with this exception when it tries to do the as JSON conversion:
org.apache.commons.lang.UnhandledException: org.codehaus.groovy.grails.web.converters.exceptions.ConverterException: Unconvertable Object of class: java.util.LinkedHashMap
I then re-wrote my unit test to just do the following:
void testEmailServiceWorks() {
def value = [test: 'test', test2: 'test2']
def valueJson = value as JSON
}
And I get the same exception when it tries to do the as JSON conversion.
Does anyone know why I'm getting this exception, and how I can fix it?
Even though you are testing a service, you can apply the #TestMixin(ControllerUnitTestMixin) annotation to your test class to get Grails to set up the JSON converter.
The as JSON magic is created when the domain framework spins up.
You have to either change your test to an integration one or mock the asType.
def setUp(){
java.util.LinkedHashMap.metaClass.asType = { Class c ->
new grails.converters."$c"(delegate)
}
}
Rember to clean up after yourself in the tearDown, you wouldn't want metaprogramming leaks in your test suite.
def tearDown(){
java.util.LinkedHashMap.metaClass.asType = null
}
Edit:
If you come from the future, consider this answer: https://stackoverflow.com/a/15485593/194932
As Grails 3.3.x grails-test-mixins plugin is deprecated. #see migration guide.
For this problem you should implement GrailsWebUnitTest which is coming from Grails Testing Support Framework.
you can initialise the JSON in the setUp() . There are various marshallers which implement ObjectMarshaller , which need to be added to the ConverterConfiguration for JSON conversion to work.
http://grails.github.io/grails-doc/2.4.4/api/index.html?org/codehaus/groovy/grails/web/converters/marshaller/json/package-summary.html
example :
DefaultConverterConfiguration<JSON> defaultConverterConfig = new DefaultConverterConfiguration<JSON>()
defaultConverterConfig.registerObjectMarshaller(new CollectionMarshaller())
defaultConverterConfig.registerObjectMarshaller(new MapMarshaller())
defaultConverterConfig.registerObjectMarshaller(new GenericJavaBeanMarshaller())
ConvertersConfigurationHolder.setTheadLocalConverterConfiguration(JSON.class, defaultConverterConfig);
I just ran into this, and I really didn't want to implement GrailsWebUnitTest as recommended in another answer here. I want to keep my service test as "pure" and lean as possible. I ended up doing this:
void setupSpec() {
defineBeans(new ConvertersGrailsPlugin())
}
void cleanupSpec() {
ConvertersConfigurationHolder.clear()
}
This is how it happens under the hood when you implement GrailsWebUnitTest (via WebSetupSpecInterceptor and WebCleanupSpecInterceptor).
That said, the converters seem to be meant for use in the web tier, primarily for making it easy to transparently return data in different formats from a controller. It's worth considering why the service you're testing needs the converters in the first place.
For example, in my case, someone used the JSON converter to serialize some data to a string so it could be stored in a single field in the database. That doesn't seem like an appropriate user of the converters, so I plan on changing how it's done. Making the converters available in my service test is a temporary solution to allow me to improve our test coverage before I refactor things.
I was getting the same error when trying to unit test a controller that calls "render myMap as JSON". We use Grails 1.3.7 and none of the other solutions worked for me without introducing other problems. Upgrading Grails was not an alternative for us at the moment.
My solution was to use JSONBuilder instead of "as JSON", like this:
render(contentType: "application/json", {myMap})
See http://docs.grails.org/latest/guide/theWebLayer.html#moreOnJSONBuilder
(I realize this is old, but came here in search for a solution and so might others)