I am working on an app that processes incoming Json's and I want to easily extract the json data and convert it to a DSL language I'v created using Xtext. My goal is to be able to later convert this data to a String that is based on my. I could probably just extract the data and manually add it to a big String variable ,but I want to do this programmatically. So ,does Xtext supports that. Is there any way to convert data to an Xtext object and later to a String (I am looking for something like json object classes)
Thanks!
If I correctly understand your question, you have already created an Xtext grammar that syntactically 'looks like' JSON.
In that case, the Xtext generated parser will be able to parse documents that follow the grammar specification (meaning they are both valid JSON and valid according to the grammar of your language).
The code that you would write looks as follows:
Package org.something.other
import com.google.inject.Injector;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.xtext.resource.XtextResourceSet;
import org.YourDSL.YourDSLStandaloneSetupGenerated;
public class ParseDocument {
public static void main(String[] args) throws IOException {
//First you use dependency injection to register the generated resource factory with EMF
Injector injector = new ourDSLStandaloneSetupGenerated().createInjectorAndDoEMFRegistration();
//Get a resource set object
XtextResourceSet resourceSet = injector.getInstance(XtextResourceSet.class);
//Register the generated EMF package
resourceSet.getPackageRegistry().put
(YourDSLPackage.eNS_URI, YourDSLPackage.eINSTANCE);
//Create an new resource with a suitable URI
Resource resource =
resourceSet.getResource(URI.createFileURI("./test.yourdsl"), true);
//You can now programmatically query and manipulate objects according to the metamodel of you DSL
MainClass root = (MainClass)resource.getContents().get(0);
}
That being said, an Xtext parser might be complete overkill depending on what you are trying to do and something like Jackson might be a better fit.
Related
I am trying to create a plugin to generate some java code and write back to the main source module. I was able to create a some simple pojo class using JavaPoet and write to the src/main/java.
To make this useful, it should read the code from src/maim/java folder and analyze the classes using reflection. Look for some annotation then generate some codes. Do I use the SourceTask for this case. Looked like I can only access the classes by the files. Is that possible to read the java classes as the class and using reflection analyze the class?
Since you specified what you want to do:
You'll need to implement an annotation processor. This has absolutely nothing to do with gradle, and a gradle plugin is actually the wrong way to go about this. Please look into Java Annotation Processor and come back with more questions if any come up.
With JavaForger you can read input classes and generate sourcecode based on that. It also provides an API to insert it into existing classes or create new classes based on the input file. In contrast to JavaPoet, JavaForger has a clear separation between code to be generated and settings on where and how to insert it. An example of a template for a pojo can look like this:
public class ${class.name}Data {
<#list fields as field>
private ${field.type} ${field.name};
</#list>
<#list fields as field>
public ${field.type} ${field.getter}() {
return ${field.name};
}
public void ${field.setter}(${field.type} ${field.name}) {
this.${field.name} = ${field.name};
}
</#list>
}
The example below uses a template called "myTemplate.javat" and adds some extra settings like creating the file if it does not exist and changing the path where the file will be created from */path/* to */pathToDto/*. The the path to the input class is given to read the class name and fields and more.
JavaForgerConfiguration config = JavaForgerConfiguration.builder()
.withTemplate("myTemplate.javat")
.withCreateFileIfNotExists(true)
.withMergeClassProvider(ClassProvider.fromInputClass(s -> s.replace("path", "pathToPojo")))
.build();
JavaForger.execute(config, "MyProject/path/inputFile.java");
If you are looking for a framework that allows changing the code more programatticaly you can also look at JavaParser. With this framework you can construct an abstract syntax tree from a java class and make changes to it.
I am writing a class that extends a class that uses Digester to parse an XML response from an API (Example existing class, code snipper below). After receiving the response, the code creates an object and adds specific methods on that.
Code snippet edited for brevity:
private Digester createDigester() {
Digester digester = new Digester();
digester.addObjectCreate("GeocodeResponse/result", GoogleGeocoderResult.class);
digester.addObjectCreate("GeocodeResponse/result/address_component", GoogleAddressComponent.class);
digester.addCallMethod("GeocodeResponse/result/address_component/long_name", "setLongName", 0);
...
digester.addSetNext("GeocodeResponse/result/address_component", "addAddressComponent");
Class<?>[] dType = {Double.class};
digester.addCallMethod("GeocodeResponse/result/formatted_address", "setFormattedAddress", 0);
...
digester.addSetNext("GeocodeResponse/result", "add");
return digester;
}
}
The API that I will be calling, however, only supports JSON. I have found a probable solution, which involves converting the JSON to XML and then running it through Digester, but that seems incredibly hackish.
public JsonDigester(final String customRootElementName) {
super(new JsonXMLReader(customRootElementName));
}
Is there a better way to do this?
This class is specifically meant to deal with XML as per the documentation:
Basically, the Digester package lets you configure an XML -> Java
object mapping module, which triggers certain actions called rules
whenever a particular pattern of nested XML elements is recognized. A
rich set of predefined rules is available for your use, or you can
also create your own.
Why would you think it would work with JSON?
I'm trying to implement a simple command-line Java app that requests some resources from a RESTful webservice. Is there a way to automatically deserialize JSON responses into my model classes?
In Objective-C there is Key-Value-Coding that allows you to create objects, access variables and methods by their string representation. This can be used to automatically deserialize an XML or JSON document into objects and this is done by some third party libraries, like RestKit.
Is there something similar for Java? I know I could use a JSON parser to get a array and map representation of the document and then create my model objects myself, but I was wondering if this could be automated?
I spent the entire evening yesterday searching for libraries, tutorials and user guides. All of them were either explaining how to build a RESTful webservice, or if it was a client app, all they ever did is download some JSON and print it to system out.
Look into Jackson
With this, you can create a class that "matches" your json data structure, and Jackson will automatically instantiate and populate the class for you. Then you're already integrated with the rest of your Java app.
Look into Google GSON, It is Google's Library for Marshaling/UnMarshaling JSON to Java and Java to JSON.
You can also look for its tutorial at http://www.mkyong.com/java/how-do-convert-java-object-to-from-json-format-gson-api/
Here an example, using XStream library: (http://x-stream.github.io/json-tutorial.html)
package com.thoughtworks.xstream.json.test;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver;
public class ReadTest {
public static void main(String[] args) {
String json = "{\"product\":{\"name\":\"Banana\",\"id\":123"
+ ",\"price\":23.0}}";
XStream xstream = new XStream(new JettisonMappedXmlDriver());
xstream.alias("product", Product.class);
Product product = (Product)xstream.fromXML(json);
System.out.println(product.getName());
}
}
I've defined a simple Xtext grammar which looks like this (simplified):
grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.common.Terminals
generate myDsl "http://www.xtext.org/example/mydsl/MyDsl"
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
System:
'Define System'
(
'Define Components' '{' components+=Component+ '}'
)
'End'
;
Component:
'Component' name=ID 'Value' value=Double ';'
;
Double returns ecore::EDouble:
'-'? INT? '.' INT
;
The problem I like to solve is - how can I convert a simple Java Object to a valid xtext file?
To simplify my problem, lets say we create a list of components in Java:
List<Component> components = new ArrayList<Component>();
components.add(new Component("FirstComponent", 1.0));
components.add(new Component("SecondComponent", 2.0));
components.add(new Component("ThirdComponent", 3.0));
The output-file I like to create should look like this:
Define System
Define Components {
Component FirstComponent Value 1.0;
Component SecondComponent Value 2.0;
Component ThirdComponent Value 3.0;
}
End
It is important that this file is checked by the xtext grammar, so that it's valid.
I Hope you have any ideas for me. Here are some of mine, but so far I don't know how to implement them:
Idea #1:
I know how to read and write a file. In my head one solution could look like this:
I have the list in my Java code, now I like to write a file which looks like the output-file above. Afterwards I like to read this file and check for errors by the grammar. How can I do this?
Idea #2:
If I imagine I would create a xml file out of Java code using JDOM, I wish I could do the same in xtext. Just define a parent "Define System" which ends with "End" (see my output-file) and then add a child "Define Components {" which ends with "}" and then add the children to this, e.g. "Component FirstComponent Value 1.0;". I hope this isn't confusing :-)
Idea #3:
I could use a template like the following and add children between the braces "{" ... "}":
Define System
Define Components { ... }
End
Btw: I already tried Linking Xtext with StringTemplate code generator, but it is kind of another problem. Hope you have any ideas.
You can use Xtext's serialization for this. Unlike Java's default Serialization API, Xtext's implementation creates the DSL.
The code would look like so:
Injector injector = Guice.createInjector(new my.dsl.MyDslRuntimeModule());
Serializer serializer = injector.getInstance(Serializer.class);
String s = serializer.serialize(eobj);
where eobj is an instance of System.
If you have written a formatter for your DSL, the output will also look nice.
Related blog post: Implement toString with Xtext's Serializer
Xtext provides an EMF-based AST for you. This AST features classes like System and Component together with their corresponding attributes, such as the Value attribute of Component. These classes are available in the src-gen folder of your language project.
To instantiate these objects, you have to use a factory class, also available in the same package.
To serialize such an AST, it is possible to reuse standard EMF tooling by creating a resource, and saving the contents. During serialization the AST is validated.
System system = ...; //Creating the AST programmatically
ResourceSet set = new ResourceSetImpl();
Resource resource = set.createResource(URI.create...URI("filename")); //Initializing an EMF resource that represents a file
resource.getContents.add(system); //adding your AST to the file resource
resource.save();
Minor remark: if you are not developing an Eclipse plug-in, you have to initialize the Xtext tooling by calling generated «YourLanguage»StandaloneSetup.doSetup() static method.
For other programmatic validation options, you can have a look at the ParseHelper and ValidatorTester classes used by the Xtext test framework.
Currently our application uses GWT-RPC for most client-server communication. Where this breaks down is when we need to auto generate images. We generate images based on dozens of parameters so what we do is build large complex urls and via a get request retrieve the dynamically built image.
If we could find a way to serialize Java objects in gwt client code and deserialize it on the server side we could make our urls much easier to work with. Instead of
http://host/page?param1=a¶m2=b¶m3=c....
we could have
http://host/page?object=?JSON/XML/Something Magicical
and on the server just have
new MagicDeserializer.(request.getParameter("object"),AwesomeClass.class);
I do not care what the intermediate format is json/xml/whatever I just really want to be able stop keeping track of manually marshalling/unmarshalling parameters in my gwt client code as well as servlets.
Use AutoBean Framework. What you need is simple and is all here http://code.google.com/p/google-web-toolkit/wiki/AutoBean
I've seen the most success and least amount of code using this library:
https://code.google.com/p/gwtprojsonserializer/
Along with the standard toString() you should have for all Object classes, I also have what's called a toJsonString() inside of each class I want "JSONable". Note, each class must extend JsonSerializable, which comes with the library:
public String toJsonString()
{
Serializer serializer = (Serializer) GWT.create(Serializer.class);
return serializer.serializeToJson(this).toString();
}
To turn the JSON string back into an object, I put a static method inside of the same class, that recreates the class itself:
public static ClassName recreateClassViaJson(String json)
{
Serializer serializer = (Serializer) GWT.create(Serializer.class);
return (ClassName) serializer.deSerialize(json, "full.package.name.ClassName");
}
Very simple!