I have a case class called Recording that I can serialize correctly using spray-json, but I can't serialize a List[Recording].
The answers I've seen about List serialization involve missing imports of DefaultJsonProtocol._ but that hasn't helped me here.
Here's the code:
import spray.json._
import scala.collection.immutable
object RecordingJsonProtocol extends DefaultJsonProtocol {
implicit val recordingFormat = jsonFormat2(Recording.apply)
}
case class Recording(name: String, hashOffsetIndex: immutable.Map[String, Int])
object RecordingLoader {
import RecordingJsonProtocol._
import DefaultJsonProtocol._
def recordingsToJson(filename: String, recordings : List[Recording]) = {
println(recordings.toJson.prettyPrint)
}
}
The error I receive is :
Error:(16, 24) Cannot find JsonWriter or JsonFormat type class for List[Recording]
println(recordings.toJson.prettyPrint)
^
Edit: problem solved
import DefaultJsonProtocol._
is redundant because RecordingJsonProtocol extends DefaultJsonProtocol -- but it's not merely redundant, it also prevents RecordingJsonProtocol from working.
Related
I have an enum defined top-level inside a Groovy class which I want to use in another class that is located in another source file:
// File: A.groovy
package com.example.pkg
class A {
static enum E {
VALUE
}
}
// File: B.groovy
package com.example.pkg
import package com.example.pkg.A
class B {
void example() {
final enumValue = A.E.VALUE
^^^^^^^^^^^^^^^^^^^^^^^^^^^ <- unable to resolve class 'A.E'
}
}
Whenever I try to access the enum the Java-way, I get an 'unable to resolve class A.E' error.
Am I doing something wrong? I cannot find any useful information online.
Thanks in advance!
Say I have the following Annotation and 2 classes:
class AppModel extends Reflectable {
final String name;
const AppModel([this.name])
: super(newInstanceCapability, metadataCapability);
}
const appModel = const AppModel();
#appModel
class ImGonnaBePickedUp {
}
#AppModel(' :( ')
class AndImNotPickedUpOnServer_IDoOnWebClient {
}
main() {
appModel.annotatedClasses // that's what I mean by "Picked Up".
}
On CmdApp side (Server): only AndImNotPickedUpOnServer_IDoOnWebClient is given in appModel.annotatedClasses.
On the web side, both classes are given.
Long story short, how do I retrieve classes annotated with direct const constructor calls like in the example above #AppModel(' :( ') (for both CmdApp and Web)?
since version 0.5.4 reflectable classes doesn't support constructors with arguments
This appears in reflectable documentation:
Footnotes: 1. Currently, the only setup which is supported is when the metadata object is an instance of a direct subclass of the class [Reflectable], say MyReflectable, and that subclass defines a const constructor taking zero arguments. This ensures that every subclass of Reflectable used as metadata is a singleton class, which means that the behavior of the instance can be expressed by generating code in the class. Generalizations of this setup may be supported in the future if compelling use cases come up.
one possible solution could be to use a second annotation to handle the name, for example:
import 'package:reflectable/reflectable.dart';
import 'package:drails_commons/drails_commons.dart';
class AppModel extends Reflectable {
const AppModel()
: super(newInstanceCapability, metadataCapability);
}
const appModel = const AppModel();
class TableName {
final String name;
const TableName(this.name);
}
#appModel
class ImGonnaBePickedUp {
}
#appModel
#TableName(' :( ')
class AndImNotPickedUpOnServer_WorksOnWebClient {
}
main() {
print(appModel.annotatedClasses); // that's what I mean by "Picked Up".
print(new GetValueOfAnnotation<TableName>()
.fromDeclaration(appModel.reflectType(AndImNotPickedUpOnServer_WorksOnWebClient)).name);
}
Note: I'm also using drails_common package
I'm perfectly willing to play with this until I get it right, but was hoping someone might give me a hint. The parameter is declared in the docs (gen-dartdocs/dart-mirrors/ClassMirror/newInstance.html) as
InstanceMirror newInstance(Symbol constructorName,
List positionalArguments,
[Map<Symbol,dynamic> namedArguments]);
There is a nice writeup on the format of positionalArguments and namedArguments in the docs. However, it is just a little on the abstract side of my current tolerance level.
A decent discussion also exists at
http://japhr.blogspot.com/2014/06/dart-factory-method-pattern.html
But, alas, no examples of actually passing args into the method.
In my case, I would like to simply pass two args, "title" and "description" into an unnamed subclass constructor.
Here's my code so far:
file: item.dart
import 'dart:mirrors';
abstract class Item {
String title;
String description;
factory Item(String type) {
MirrorSystem libs = currentMirrorSystem();
LibraryMirror lib = libs.findLibrary(new Symbol('app.models'));
Map<Symbol, Mirror> classes = lib.declarations;
// To do: handle exception if class not found
ClassMirror cls = classes[new Symbol(type)];
// TODO:
// verify each subclass has no-arg ctor
// determ how to pass args to ctor.
InstanceMirror inst = cls.newInstance(new Symbol(''), []);
return inst.reflectee;
}
// conflicts w/ Item factory
// Item(this.title, this.description);
}
And here's the class that gets instantiated:
file: model.dart
library app.models;
import 'item.dart' show Item;
/// The barebones model for a codelab. Defines constants used for validation.
class Codelab implements Item {
// ...
}
Finally, here is how the Item factory is called. ItemElement is the superclass of its own hierarchy, subclassed by CodelabElement:
file: item_element.dart:
import 'item.dart' show Item;
class ItemElement {
Item item;
final String itemType;
ItemElement() {
item = new Item(itemType);
}
// ...
}
And CodelabElement:
file: codelab_element.dart
import 'model.dart' show Codelab;
import 'item_element.dart' show ItemElement;
class CodelabElement extends ItemElement {
final itemType = "Codelab";
CodelabElement() : super() {}
//...
}
And then:
file: main.dart
void main() {
var element = new CodelabElement();
}
Currently, the new Codelab instance is returned from newInstance() (very cool), but it doesn't contain the inherited 'title' and 'description' attrs.
Maybe it has something to do with my being unclear on the usage of "extends" and "implements".
This should work
cls.newInstance(new Symbol(''), ['a', 1] /*,
{#arg1Name: 'arg1Value', #arg2Name: 'arg2Value'}*/ );
and is like
new MyClass('a', 1, arg1Name: 'arg1Value' /*, arg2Name: 'arg2Value'*/);
Just saw, Named arguments are not implemented.
You can try it in DartPad
I'm trying to get the properties of a dynamic Class name (also trying to instantiate it) but the next code doesn't work because I think I need to import the dart file that has the Class code in the file where I want to reflect it:
//I import the file in other Dart file
import 'MyClass.dart'; //This only have a class named MyClass with some properties
import 'OtherClass.dart'
class mainClass {
void mainFunction () {
var properties = OtherClass.getProperties('MyClass');
}
}
Here is the OtherClass contents:
import "dart:mirrors";
class OtherClass {
static getProperties (String className) {
ClassMirror cm = reflectClass(className);
for (var m in cm.declarations.values)
print(MirrorSystem.getName(m.simpleName));
}
}
is there anyway to reflect a class that is not imported in the actual Dart file?
Hope this makes sense, thanks in advance.
You need to find the library containing the class first. Use currentMirrorSystem().libraries to get all libraries imported in your application. If you want to avoid disambiguities, add unique library declarations to your library and pass the library name to getProperties() for exact lookups.
import "dart:mirrors";
class OtherClass {
static getProperties(String className) {
var classSymbol = new Symbol(className);
var libs = currentMirrorSystem().libraries;
var foundLibs = libs.keys.where((lm) =>
libs[lm].declarations.containsKey(classSymbol) &&
libs[lm].declarations[classSymbol] is ClassMirror);
if (foundLibs.length != 1) {
throw 'None or more than one library containing "${className}" class found';
}
ClassMirror cm = libs[foundLibs.first].declarations[classSymbol];
for (var m
in cm.declarations.values) print(MirrorSystem.getName(m.simpleName));
}
}
I'm having a tree of domain classes that i want to convert to JSON via a deep converter:
import grails.converters.deep.JSON
deepObject as JSON
Somewhere in the tree I'm having Double.NaN values in some fields and the JSON parser throws an exception:
org.apache.commons.lang.UnhandledException: org.codehaus.groovy.grails.web.converters.exceptions.ConverterException: org.codehaus.groovy.grails.web.json.JSONException: JSON does not allow non-finite numbers
How can I handle that case? May be returning a string ('NaN').
I tried repacing the JSONObject.testValidity(Object o) method, but this is a pojo and so it does not work.
Edit
I also tried to register a marshaller in Bootstrap.groovy:
JSON.registerObjectMarshaller(Double) {
return it == Double.NaN ? 'NaN' : it.toString()
}
But it also wont work.
Unfortunately most native values rendering is hardcoded in grails.converters.JSON, and can't be personalized with registerObjectMarshaller. One solution is to specify the JSON converter class and override its value(Object o) method as:
import grails.converters.JSON
class MyJSONConverter extends JSON {
#Override
public void value(Object o) throws ConverterException {
if (o instanceof Double && o.NaN)
o = 'Nan'
super.value(o);
}
}
and call your custom implementation with
import org.grails.web.converters.ConverterUtil
import org.grails.web.servlet.mvc.GrailsWebRequest
MyJSONConverter myJSONConverter = ConverterUtil.createConverter( MyJSONConverter.class, deepObject, GrailsWebRequest.lookup()?.applicationContext);
String deepString = myJSONConverter as String;