In a Java Maven project, how do you generate java source files from JSON? For example we have
{
"firstName": "John",
"lastName": "Smith",
"address": {
"streetAddress": "21 2nd Street",
"city": "New York"
}
}
When we run mvn generate-sources we want it to generate something like this:
class Address {
JSONObject mInternalJSONObject;
Address (JSONObject json){
mInternalJSONObject = json;
}
String getStreetAddress () {
return mInternalJSONObject.getString("streetAddress");
}
String getCity (){
return mInternalJSONObject.getString("city");
}
}
class Person {
JSONObject mInternalJSONObject;
Person (JSONObject json){
mInternalJSONObject = json;
}
String getFirstName () {
return mInternalJSONObject.getString("firstName");
}
String getLastName (){
return mInternalJSONObject.getString("lastName");
}
Address getAddress (){
return Address(mInternalJSONObject.getString("address"));
}
}
As a Java developer, what lines of XML do I need to write in my pom.xml in order to make this happen?
Try http://www.jsonschema2pojo.org
Or the jsonschema2pojo plug-in for Maven:
<plugin>
<groupId>org.jsonschema2pojo</groupId>
<artifactId>jsonschema2pojo-maven-plugin</artifactId>
<version>1.0.2</version>
<configuration>
<sourceDirectory>${basedir}/src/main/resources/schemas</sourceDirectory>
<targetPackage>com.myproject.jsonschemas</targetPackage>
<sourceType>json</sourceType>
</configuration>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
</plugin>
The <sourceType>json</sourceType> covers the case where the sources are json (like the OP). If you have actual json schemas, remove this line.
Updated in 2014: Two things have happened since Dec '09 when this question was asked:
The JSON Schema spec has moved on a lot. It's still in draft (not finalised) but it's close to completion and is now a viable tool specifying your structural rules
I've recently started a new open source project specifically intended to solve your problem: jsonschema2pojo. The jsonschema2pojo tool takes a json schema document and generates DTO-style Java classes (in the form of .java source files). The project is not yet mature but already provides coverage of the most useful parts of json schema. I'm looking for more feedback from users to help drive the development. Right now you can use the tool from the command line or as a Maven plugin.
If you're using Jackson (the most popular library there), try
https://github.com/astav/JsonToJava
Its open source (last updated on Jun 7, 2013 as of year 2021) and anyone should be able to contribute.
Summary
A JsonToJava source class file generator that deduces the schema based on supplied sample json data and generates the necessary java data structures.
It encourages teams to think in Json first, before writing actual code.
Features
Can generate classes for an arbitrarily complex hierarchy (recursively)
Can read your existing Java classes and if it can deserialize into those structures, will do so
Will prompt for user input when ambiguous cases exist
Here's an online tool that will take JSON, including nested objects or nested arrays of objects and generate a Java source with Jackson annotations.
Answering this old question with recent project ;-).
At the moment the best solution is probably JsonSchema2Pojo :
It does the job from the seldom used Json Schema but also with plain Json. It provides Ant and Maven plugin and an online test application can give you an idea of the tool. I put a Json Tweet and generated all the containing class (Tweet, User, Location, etc..).
We'll use it on Agorava project to generate Social Media mapping and follow the contant evolution in their API.
Thanks all who attempted to help. For me this script was helpful. It process only flat JSON and don't take care of types, but automate some routine
String str =
"{"
+ "'title': 'Computing and Information systems',"
+ "'id' : 1,"
+ "'children' : 'true',"
+ "'groups' : [{"
+ "'title' : 'Level one CIS',"
+ "'id' : 2,"
+ "'children' : 'true',"
+ "'groups' : [{"
+ "'title' : 'Intro To Computing and Internet',"
+ "'id' : 3,"
+ "'children': 'false',"
+ "'groups':[]"
+ "}]"
+ "}]"
+ "}";
JSONObject json = new JSONObject(str);
Iterator<String> iterator = json.keys();
System.out.println("Fields:");
while (iterator.hasNext() ){
System.out.println(String.format("public String %s;", iterator.next()));
}
System.out.println("public void Parse (String str){");
System.out.println("JSONObject json = new JSONObject(str);");
iterator = json.keys();
while (iterator.hasNext() ){
String key = iterator.next();
System.out.println(String.format("this.%s = json.getString(\"%s\");",key,key ));
System.out.println("}");
I'm aware this is an old question, but I stumbled across it while trying to find an answer myself.
The answer that mentions the online json-pojo generator (jsongen) is good, but I needed something I could run on the command line and tweak more.
So I wrote a very hacky ruby script to take a sample JSON file and generate POJOs from it. It has a number of limitations (for example, it doesn't deal with fields that match java reserved keywords) but it does enough for many cases.
The code generated, by default, annotates for use with Jackson, but this can be turned off with a switch.
You can find the code on github: https://github.com/wotifgroup/json2pojo
I created a github project Json2Java that does this.
https://github.com/inder123/json2java
Json2Java provides customizations such as renaming fields, and creating inheritance hierarchies.
I have used the tool to create some relatively complex APIs:
Gracenote's TMS API: https://github.com/inder123/gracenote-java-api
Google Maps Geocoding API: https://github.com/inder123/geocoding
I had the same problem so i decided to start writing a small tool to help me with this. Im gonna share andopen source it.
https://github.com/BrunoAlexandreMendesMartins/CleverModels
It supports, JAVA, C# & Objective-c from JSON .
Feel free to contribute!
I know there are many answers but of all these I found this one most useful for me. This link below gives you all the POJO classes in a separate file rather than one huge class that some of the mentioned websites do:
https://json2csharp.com/json-to-pojo
It has other converters too. Also, it works online without a limitation in size. My JSON is huge and it worked nicely.
As far as I know there is no such tool. Yet.
The main reason is, I suspect, that unlike with XML (which has XML Schema, and then tools like 'xjc' to do what you ask, between XML and POJO definitions), there is no fully features schema language. There is JSON Schema, but it has very little support for actual type definitions (focuses on JSON structures), so it would be tricky to generate Java classes. But probably still possible, esp. if some naming conventions were defined and used to support generation.
However: this is something that has been fairly frequently requested (on mailing lists of JSON tool projects I follow), so I think that someone will write such a tool in near future.
So I don't think it is a bad idea per se (also: it is not a good idea for all use cases, depends on what you want to do ).
You could also try GSON library. Its quite powerful it can create JSON from collections, custom objects and works also vice versa. Its released under Apache Licence 2.0 so you can use it also commercially.
http://code.google.com/p/google-gson/
Try my solution
http://htmlpreview.github.io/?https://raw.githubusercontent.com/foobnix/android-universal-utils/master/json/generator.html
{
"auctionHouse": "sample string 1",
"bidDate": "2014-05-30T08:20:38.5426521-04:00 ",
"bidPrice": 3,
"bidPrice1": 3.1,
"isYear":true
}
Result Java Class
private String auctionHouse;
private Date bidDate;
private int bidPrice;
private double bidPrice1;
private boolean isYear;
JSONObject get
auctionHouse = obj.getString("auctionHouse");
bidDate = obj.opt("bidDate");
bidPrice = obj.getInt("bidPrice");
bidPrice1 = obj.getDouble("bidPrice1");
isYear = obj.getBoolean("isYear");
JSONObject put
obj.put("auctionHouse",auctionHouse);
obj.put("bidDate",bidDate);
obj.put("bidPrice",bidPrice);
obj.put("bidPrice1",bidPrice1);
obj.put("isYear",isYear);
To add to #japher's post. If you are not particularly tied to JSON, Protocol Buffers is worth checking out.
Related
I have a complex JSON from server which needs to be turned into java objects.
{"menus":[{"title":"Jewellery","menu_columns":[{"title":"category","menu_items":[{"title":"Earrings"},{"title":"Necklaces"},{"title":"Necklace Sets"},{"title":"Anklets"},{"title":"Mangalsutra"},{"title":"Pendants"},{"title":"Bangles \u0026 Bracelets"},{"title":"Rings"},{"title":"Maang Tikka"},{"title":"Keychains"},{"title":"Baju Band"},{"title":"Brooch"},{"title":"Hair Pins"},{"title":"Jewellery Box"},{"title":"Nose Ring"},{"title":"Waist Belts"},{"title":"Jewellery Combo"},{"title":"Watches"},{"title":"Other"}]},{"title":"Type","menu_items":[{"title":"Bridal Jewellery"},{"title":"Temple Jewellery"},{"title":"Statement Jewellery"},{"title":"Thewa Jewellery"},{"title":"Handmade Jewellery"},{"title":"Filigree Jewellery"},{"title":"Pearl Jewellery"},{"title":"High End Jewellery"},{"title":"Ethnic Jewellery"},{"title":"Kundan Jewellery"},{"title":"Jhumkas"}]},{"title":"Earrings","menu_items":[]}]},{"title":"Sarees","menu_columns":[{"title":"by fabric","menu_items":[{"title":"Cotton Sarees"},{"title":"Art Silk Sarees"},{"title":"Georgette Sarees"},{"title":"Chiffon Sarees"},{"title":"Net Sarees"},{"title":"Crepe Sarees"},{"title":"Silk Sarees"},{"title":"Viscose Sarees"},{"title":"Tissue Sarees"},{"title":"Satin Sarees"},{"title":"Velvet Sarees"},{"title":"Jute Sarees"},{"title":"Brasso Sarees"},{"title":"Shimmer Sarees"},{"title":"Brocade Sarees"},{"title":"Jacquard Sarees"},{"title":"Dupion Sarees"},{"title":"Saree Blouses"},{"title":"Sarees Combo"}]},{"title":"by type","menu_items":[{"title":"Supernet Sarees"},{"title":"Banarasi Sarees"},{"title":"Banarasi Silk Sarees"},{"title":"Kalamkari Sarees"},{"title":"Chanderi Sarees"},{"title":"Tussar Silk Sarees"},{"title":"Organza Sarees"},{"title":"Wedding Sarees"},{"title":"Printed Sarees"},{"title":"Lehenga Sarees"},{"title":"Bhagalpuri Silk Sarees"},{"title":"Heavy Work Sarees"},{"title":"Party Wear Sarees"},{"title":"Traditional Sarees"},{"title":"One Minute Sarees"},{"title":"Kerala Sarees"},{"title":"Bandhani Sarees"},{"title":"Ikat Sarees"},{"title":"Hand Woven Sarees"}]},{"title":"bollywood sarees","menu_items":[{"title":"Kareena Kapoor Sarees"},{"title":"Katrina Kaif Saree"},{"title":"Madhuri Dixit Sarees"},{"title":"Deepika Padukone Saree"},{"title":"Priyanka Chopra Saree"},{"title":"Sridevi Sarees"},{"title":"Anushka Sharma Saree"},{"title":"Shilpa Shetty Sarees"},{"title":"Sonakshi Sinha Saree"},{"title":"Bipasha Basu Sarees"},{"title":"Aishwarya Rai Saree"},{"title":"Sonam Kapoor Saree"},{"title":"Vidya Balan Saree"}]}]},{"title":"Salwar Kameez","menu_columns":[{"title":"","menu_items":[{"title":"Dress Materials"},{"title":"Anarkali Salwar Kameez"},{"title":"Cotton Salwar Kameez"},{"title":"Party Wear Salwar Kameez"},{"title":"Pakistani"},{"title":"Wedding"},{"title":"Salwars \u0026 Churidars"},{"title":"Semi Stitched Salwar Suits"},{"title":"Bollywood Salwars"},{"title":"Salwar Combo"}]}]},{"title":"More","menu_columns":[{"title":"bridal","menu_items":[{"title":"Bridal Sets"},{"title":"Bridal Lehengas"},{"title":"Bridal Sarees"}]},{"title":"lehengas","menu_items":[{"title":"Ghagra Choli"},{"title":"Lehenga Choli"},{"title":"Bollywood Lehengas"}]},{"title":"bags","menu_items":[{"title":"Hand Bags"},{"title":"Clutches"},{"title":"Wallets"},{"title":"Tote Bags"},{"title":"Backpacks"},{"title":"Sling Bags"},{"title":"Potli Bags"}]},{"title":"other apparel","menu_items":[{"title":"Kurtas \u0026 Kurtis"},{"title":"Tops"},{"title":"Stoles \u0026 Dupattas"},{"title":"Tunics"},{"title":"Leggings"},{"title":"Shawls"},{"title":"Dresses"},{"title":"Skirts"}]}]},{"title":"Home Decor","menu_columns":[{"title":"accessories","menu_items":[{"title":"Wall Decals"},{"title":"Wall Clocks"},{"title":"Ipad Covers"},{"title":"Laptop Skins"},{"title":"Phone Cases"},{"title":"Candles"},{"title":"Flowers"},{"title":"Artificial Flowers"},{"title":"Table Lamps"},{"title":"Trays"},{"title":"Vases"},{"title":"Wall Art"},{"title":"Tea Kettle"},{"title":"Paintings"},{"title":"Stationery"},{"title":"Photo Frames"},{"title":"Decorative Plates"},{"title":"Pots"},{"title":"Sculptures"},{"title":"Other"}]},{"title":"furnishing","menu_items":[{"title":"Pillow Covers"},{"title":"Bed Sheets"},{"title":"Duvet Covers"},{"title":"Quilts"},{"title":"Table Cloth"},{"title":"Table Mats \u0026 Runner"},{"title":"Carpets"},{"title":"Jaipuri Razai"},{"title":"Other"}]}]},{"title":"Gifts","menu_columns":[{"title":"by recipients","menu_items":[{"title":"For Him"},{"title":"For Her"},{"title":"For Kids"},{"title":"For Dad"},{"title":"For Mom"},{"title":"For Husband"},{"title":"For Wife"},{"title":"For Boyfriend"},{"title":"For Girlfriend"},{"title":"For Brother"},{"title":"For Sister"}]},{"title":"by occasions","menu_items":[{"title":"Birthday"},{"title":"Engagement"},{"title":"Wedding"},{"title":"Anniversary"},{"title":"Congratulation"},{"title":"House Warming"},{"title":"Office Opening"}]},{"title":"by festivals","menu_items":[{"title":"Christmas Gifts"},{"title":"Christmas Decorations"},{"title":"Valentine Gifts"},{"title":"Ganesh Chaturthi"},{"title":"Rakhi Online"},{"title":"New Year"},{"title":"Teachers Day"},{"title":"Engineers Day"},{"title":"Thanksgiving"},{"title":"Onam gifts"},{"title":"Navratri lehenga Chaniya Choli"},{"title":"Diwali Gifts"}]}]},{"title":"Lehenga","menu_columns":[]}]}
I would like to save time writing the Java objects (models) corresponding to such a complex JSON manually.
Are there any tools which can help convert this complex JSON into java models quickly?
I had a look at http://www.jsonschema2pojo.org/ but I think it was not generating the correct Java POJOs. I'm not looking for libraries for converting JSON into java objects(like GSON, Jackson) but for online tools for generating the java model classes.
I wrote a simple JavaScript tool to automatically generate the java class files. It only works on Chrome browser. Here is the link:
http://www.karvitech.com/Json2Java.html
can you have a look at Gson API. I am currently using it in my project and it is working fine for me...
Think about Jackson library.
Simply use ObjectMapper readValue() and writeValue()
The best explanation I found in the past is here: http://www.mkyong.com/java/how-to-convert-java-object-to-from-json-jackson
a general question:
We are launching a new ITSM Toolsuite in our company called ServiceNow.
ServiceNow offers a lot of nice out-of-the-box Webservices.
Currenty we are implementing some interfaces to other interal systems and we use these Webservices to consume data of Servicenow.
How we did it in PHP:
<?php
$credentials = array('login'=>'user', 'password'=>'pass');
$client = new SoapClient("https://blah.com/incident.do?WSDL", $credentials);
$params = array('param1' => 'value1', 'param1' => 'value1');
$result = $client->__soapCall('getRecords', array('parameters' => $params));
// result array stored in $result->getRecordsResult
?>
And thats it! 5 minutes of work, Beautiful and simple - from my point of view.
Ok and now the same in Java:
I did some research and it seems everbody is using Apache Axis2 for consuming Webservices in Java. So I decided to go down that road.
Install Apache Axis
open cygwin or cmd and generate Classes from WSDL.. WTF? what for?
$ ./wsdl2java.sh -uri https://blah.com/incident.do?WSDL
copy generated classes to Java Project in Eclipse.
Use this classes:
ServiceNow_incidentStub proxy = new ServiceNow_incidentStub();
proxy._getServiceClient().getOptions().setProperty(org.apache.axis2.transport.http.HTTPConstants.CHUNKED, Boolean.FALSE);
ServiceNow_incidentStub.GetRecords defectsGetRecords = new ServiceNow_incidentStub.GetRecords();
ServiceNow_incidentStub.GetRecordsResponse defectsResult = new ServiceNow_incidentStub.GetRecordsResponse();
proxy._getServiceClient().getOptions().setManageSession(true);
HttpTransportProperties.Authenticator basicAuthentication = new HttpTransportProperties.Authenticator();
basicAuthentication.setUsername("user");
basicAuthentication.setPassword("pass");
proxy._getServiceClient().getOptions().setProperty(org.apache.axis2.transport.http.HTTPConstants.AUTHENTICATE, basicAuthentication);
defectsResult = proxy.getRecords(defectsGetRecords);
com.service_now.www.ServiceNow_incidentStub.GetRecordsResult_type0[] defects = defectsResult.getGetRecordsResult();
for (int j=0; j < defects.length; j++) {
// do something
}
Its working but I think this way is very complicated..
everytime something in the wsdl changes - i must recompile them with axis.
There is no way to configure something globally like Soap-endpoint or something like that.
Is there an easier way in Java to consume SOAP with a WSDL??
First off: I completely agree. I do quite a bit of work with Web Services and ServiceNow, and using Java and/Or .Net is quite different than using a scripted language (I usually use Perl for scripts). The inherent issue comes into the fact that a WSDL should not be changing that often, especially in production. The idea in Java and .Net is that you get these stub classes to get compile time error checking.
If your currently in a Ph1 and haven't deployed Prod yet, then you should really look into how often that WSDL will be changing. Then make your decision from there on which technology to use. The nice thing is that even if the WSDL changes, posting data to the instance - almost all of the fields are optional. So if a new field is added it's not a big deal. The issue comes in when data is returned (most of the time) because many times java and .net will throw an exception if the returned XML is not in the structure it is expecting.
One thing that many people do is setup Modules as CI's in the CMDB and maintain their ServiceNow instance through the Change Request module. That way your java application will be a downstream CI to whatever module/table you are querying, and when a CR is put in to modify that table, it will be known immediately that there will be an impact on your internal application as well.
Unfortunately you are right though, that is a trade off with the different languages and from my experience there is very little we can do to change that.
One thing I forgot to add, another option for you is to use the JSON service instead. That will allow you to make raw requests to the SNC instance then use a JSON parser to parse that data for you "on the fly" so to speak. It takes away the compile time checking but also takes away many of the flaws of the SOAP system.
IF you are using maven, try using this plugin.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>axistools-maven-plugin</artifactId>
<version>1.4</version>
<configuration>
<urls>
<url>https://blah.com/incident.do?WSDL</url>
</urls>
<packageSpace>your.destination.package</packageSpace>
<serverSide>true</serverSide>
<outputDirectory>src/main/java</outputDirectory>
</configuration>
<executions>
<execution>
<goals><goal>wsdl2java</goal></goals>
</execution>
</executions>
</plugin>
I was also trying to access ServiceNow from Java using Eclipse, and it seemed to me that the Axis2 approach was overly restrictive given how ServiceNow designed their API, so I wrote my own package to generate SOAP calls dynamically using JDOM. Here is an example of what the code looks like:
Instance instance = new Instance("https://blah.service-now.com", "username", "password");
GlideFilter filter = new GlideFilter("category=network^active=true");
GlideRecordIterator iter = instance.table("incident").
bulkFetcher().setFilter(filter).getAllRecords().iterator();
while (iter.hasNext()) {
GlideRecord rec = iter.next();
System.out.println(
rec.getField("number") + " " + rec.getField("short_description"));
}
A couple of things about this code:
I use run-time validation rather than build-time validation. If you mistakenly type getField("shortdescription") the code throws an InvalidFieldNameException.
Queries are not bound by ServiceNow's normal 250 record limit because the BulkFetcher loops internally making as many Web Service calls as necessary to retrieve all the data.
The package source code is at https://sourceforge.net/projects/servicenowpump/
I consume lots of Soap services with PHP in the company I work for, and I would always suggest generating classes for the request and response data structure. Otherwise you will easily get lost - PHP does not preserve any remains of the original XML structure, it will all be converted to arrays and stdClass objects.
Getting classes created from the WSDL description is not that easy in PHP, as there are only a few scripts that do this - and they all have their shortcomings when it comes to WSDL files that make use of the more obscure parts of the SOAP standard. After that, you somehow have to make these classes available to your PHP script. If this is hard for you, it is a sign of a not too well organized code base. With the autoloading feature it works like a charm.
But yes, this step is entirely optional for PHP. If using only one Soap service, it'll probably make no difference.
data: [
{
type: "earnings"
info: {
earnings: 45.6
dividends: 4052.94
gains: 0
expenses: 3935.24
shares_bought: 0
shares_bought_user_count: 0
shares_sold: 0
shares_sold_user_count: 0
}
created: "2011-07-04 11:46:17"
}
{
type: "mentions"
info: [
{
type_id: "twitter"
mentioner_ticker: "LOANS"
mentioner_full_name: "ERICK STROBEL"
}
]
created: "2011-06-10 23:03:02"
}
]
Here's my problem : like you can see the "info" is different in each of one, one is a json object, and one is a json array, i usually choose Gson to take the data, but with Gson we can't do this kind of thing . How can i make it work ?
If you want to use Gson, then to handle the issue where the same JSON element value is sometimes an array and sometimes an object, custom deserialization processing is necessary. I posted an example of this in the Parsing JSON with GSON, object sometimes contains list sometimes contains object post.
If the "info" element object has different elements based on type, and so you want polymorphic deserialization behavior to deserialize to the correct type of object, with Gson you'll also need to implement custom deserialization processing. How to do that has been covered in other StackOverflow.com posts. I posted a link to four different such questions and answers (some with code examples) in the Can I instantiate a superclass and have a particular subclass be instantiated based on the parameters supplied thread. In this thread, the particular structure of the JSON objects to deserialize varies from the examples I just linked, because the element to indicate the type is external of the object to be deserialized, but if you can understand the other examples, then handling the problem here should be easy.
Both key and value have to be within quotes, and you need to separate definitions with commas:
{
"key0": "value0",
"key1": "value1",
"key2": [ "value2_0", "value2_1" ]
}
That should do the trick!
The info object should be of the same type with every type.
So check the type first. Pseudocode:
if (data.get('type').equals("mentions") {
json_arr = data.get('info');
}
else if (data.get('type').equals("earnings") {
json_obj = data.get('info');
}
I'm not sure that helps, cause I'm not sure I understand the question.
Use simply org.json classes that are available in android: http://developer.android.com/reference/org/json/package-summary.html
You will get a dynamic structure that you will be able to traverse, without the limitations of strong typing.....
This is not a "usual" way of doing things in Java (where strong typing is default) but IMHO in many situations even in Java it is ok to do some dynamic processing. Flexibility is better but price to pay is lack of compile-time type verification... Which in many cases is ok.
If changing libraries is an option you could have a look at Jackson, its Simple Data Binding mode should allow you to deserialize an object like you describe about. A part of the doc that is probably quite important is this, your example would already need JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES to work...
Clarification for Bruce: true, in Jackson's Full Data Binding mode, but not in Simple Data Binding mode. This is simple data binding:
public static void main(String[] args) throws IOException {
File src = new File("test.json");
ObjectMapper mapper = new ObjectMapper();
mapper.configure(JsonParser.Feature. ALLOW_UNQUOTED_FIELD_NAMES, true);
mapper.configure(JsonParser.Feature.ALLOW_COMMENTS,true);
Object root = mapper.readValue(src, Object.class);
Map<?,?> rootAsMap = mapper.readValue(src, Map.class);
System.out.println(rootAsMap);
}
which with OP's sightly corrected sample JSON data gives:
{data=[{type=earnings, info={earnings=45.6, dividends=4052.94, gains=0,
expenses=3935.24, shares_bought=0, shares_bought_user_count=0, shares_sold=0,
shares_sold_user_count=0}, created=2011-07-04 11:46:17}, {type=mentions,
info=[{type_id=twitter, mentioner_ticker=LOANS, mentioner_full_name=ERICK STROBEL}],
created=2011-06-10 23:03:02}]}
OK, some hand-coding needed to wire up this Map to the original data, but quite often less is more and such mapping code, being dead simple has the advantage of being very easy to read/maintain later on.
I would like to read a pom.xml in Java code. I wonder if there is a library for that, so I can have an iterator for different sections, e.g., dependenes, plugins, etc. I want to avoid to build a parser by hand.
You can try MavenXpp3Reader which is part of maven-model. Sample code:
MavenXpp3Reader reader = new MavenXpp3Reader();
Model model = reader.read(new FileReader(mypom));
Firstly, I'm assuming you are not already running inside a Maven plugin, as there are easier ways to achieve that with the available APIs there.
The MavenXpp3Reader solution posted earlier will allow you to read the POM easily, however does not take into account inheritance of the parent and interpolation of expressions.
For that, you would need to use the ModelBuilder class.
Use of this is quite simple, for example from Archiva is this code fragment:
ModelBuildingRequest req = new DefaultModelBuildingRequest();
req.setProcessPlugins( false );
req.setPomFile( file );
req.setModelResolver( new RepositoryModelResolver( basedir, pathTranslator ) );
req.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
Model model;
try
{
model = builder.build( req ).getEffectiveModel();
}
catch ( ModelBuildingException e )
{
...
}
You must do two things to run this though:
instantiate and wire an instance of ModelBuilder including its private fields
use one of Maven's resolvers for finding the parent POMs, or write your own (as is the case in the above snippet)
How best to do that depends on the DI framework you are already using, or whether you want to just embed Maven's default container.
This depends on what you're trying to achieve. If you just want to treat it as an XML with embedded XML files, go with suggestions already offered.
If you are looking to implement some form of Maven functionality into your app, you could try the new aether library. I haven't used it, but it looks simple enough to integrate and should offer Maven functionality with little effort on your part.
BTW, this library is a Maven 3 lib, not Maven 2 (as specified in your tag). Don't know if that makes much difference to you
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 7 years ago.
Improve this question
I'm looking for a framework to generate Java source files.
Something like the following API:
X clazz = Something.createClass("package name", "class name");
clazz.addSuperInterface("interface name");
clazz.addMethod("method name", returnType, argumentTypes, ...);
File targetDir = ...;
clazz.generate(targetDir);
Then, a java source file should be found in a sub-directory of the target directory.
Does anyone know such a framework?
EDIT:
I really need the source files.
I also would like to fill out the code of the methods.
I'm looking for a high-level abstraction, not direct bytecode manipulation/generation.
I also need the "structure of the class" in a tree of objects.
The problem domain is general: to generate a large amount of very different classes, without a "common structure".
SOLUTIONS
I have posted 2 answers based in your answers... with CodeModel and with Eclipse JDT.
I have used CodeModel in my solution, :-)
Sun provides an API called CodeModel for generating Java source files using an API. It's not the easiest thing to get information on, but it's there and it works extremely well.
The easiest way to get hold of it is as part of the JAXB 2 RI - the XJC schema-to-java generator uses CodeModel to generate its java source, and it's part of the XJC jars. You can use it just for the CodeModel.
Grab it from http://codemodel.java.net/
Solution found with CodeModel
Thanks, skaffman.
For example, with this code:
JCodeModel cm = new JCodeModel();
JDefinedClass dc = cm._class("foo.Bar");
JMethod m = dc.method(0, int.class, "foo");
m.body()._return(JExpr.lit(5));
File file = new File("./target/classes");
file.mkdirs();
cm.build(file);
I can get this output:
package foo;
public class Bar {
int foo() {
return 5;
}
}
Solution found with Eclipse JDT's AST
Thanks, Giles.
For example, with this code:
AST ast = AST.newAST(AST.JLS3);
CompilationUnit cu = ast.newCompilationUnit();
PackageDeclaration p1 = ast.newPackageDeclaration();
p1.setName(ast.newSimpleName("foo"));
cu.setPackage(p1);
ImportDeclaration id = ast.newImportDeclaration();
id.setName(ast.newName(new String[] { "java", "util", "Set" }));
cu.imports().add(id);
TypeDeclaration td = ast.newTypeDeclaration();
td.setName(ast.newSimpleName("Foo"));
TypeParameter tp = ast.newTypeParameter();
tp.setName(ast.newSimpleName("X"));
td.typeParameters().add(tp);
cu.types().add(td);
MethodDeclaration md = ast.newMethodDeclaration();
td.bodyDeclarations().add(md);
Block block = ast.newBlock();
md.setBody(block);
MethodInvocation mi = ast.newMethodInvocation();
mi.setName(ast.newSimpleName("x"));
ExpressionStatement e = ast.newExpressionStatement(mi);
block.statements().add(e);
System.out.println(cu);
I can get this output:
package foo;
import java.util.Set;
class Foo<X> {
void MISSING(){
x();
}
}
You can use Roaster (https://github.com/forge/roaster) to do code generation.
Here is an example:
JavaClassSource source = Roaster.create(JavaClassSource.class);
source.setName("MyClass").setPublic();
source.addMethod().setName("testMethod").setPrivate().setBody("return null;")
.setReturnType(String.class).addAnnotation(MyAnnotation.class);
System.out.println(source);
will display the following output:
public class MyClass {
private String testMethod() {
return null;
}
}
Another alternative is Eclipse JDT's AST which is good if you need to rewrite arbitrary Java source code rather than just generate source code.
(and I believe it can be used independently from eclipse).
The Eclipse JET project can be used to do source generation. I don't think it's API is exactly like the one you described, but every time I've heard of a project doing Java source generation they've used JET or a homegrown tool.
Don't know of a library, but a generic template engine might be all you need. There are a bunch of them, I personally have had good experience with FreeMarker
I built something that looks very much like your theoretical DSL, called "sourcegen", but technically instead of a util project for an ORM I wrote. The DSL looks like:
#Test
public void testTwoMethods() {
GClass gc = new GClass("foo.bar.Foo");
GMethod hello = gc.getMethod("hello");
hello.arguments("String foo");
hello.setBody("return 'Hi' + foo;");
GMethod goodbye = gc.getMethod("goodbye");
goodbye.arguments("String foo");
goodbye.setBody("return 'Bye' + foo;");
Assert.assertEquals(
Join.lines(new Object[] {
"package foo.bar;",
"",
"public class Foo {",
"",
" public void hello(String foo) {",
" return \"Hi\" + foo;",
" }",
"",
" public void goodbye(String foo) {",
" return \"Bye\" + foo;",
" }",
"",
"}",
"" }),
gc.toCode());
}
https://github.com/stephenh/joist/blob/master/util/src/test/java/joist/sourcegen/GClassTest.java
It also does some neat things like "Auto-organize imports" any FQCNs in parameters/return types, auto-pruning any old files that were not touched in this codegen run, correctly indenting inner classes, etc.
The idea is that generated code should be pretty to look at it, with no warnings (unused imports, etc.), just like the rest of your code. So much generated code is ugly to read...it's horrible.
Anyway, there is not a lot of docs, but I think the API is pretty simple/intuitive. The Maven repo is here if anyone is interested.
If you REALLY need the source, I don't know of anything that generates source. You can however use ASM or CGLIB to directly create the .class files.
You might be able to generate source from these, but I've only used them to generate bytecode.
I was doing it myself for a mock generator tool. It's a very simple task, even if you need to follow Sun formatting guidelines. I bet you'd finish the code that does it faster then you found something that fits your goal on the Internet.
You've basically outlined the API yourself. Just fill it with the actual code now!
There is also StringTemplate. It is by the author of ANTLR and is quite powerful.
There is new project write-it-once. Template based code generator. You write custom template using Groovy, and generate file depending on java reflections. It's the simplest way to generate any file. You can make getters/settest/toString by generating AspectJ files, SQL based on JPA annotations, inserts / updates based on enums and so on.
Template example:
package ${cls.package.name};
public class ${cls.shortName}Builder {
public static ${cls.name}Builder builder() {
return new ${cls.name}Builder();
}
<% for(field in cls.fields) {%>
private ${field.type.name} ${field.name};
<% } %>
<% for(field in cls.fields) {%>
public ${cls.name}Builder ${field.name}(${field.type.name} ${field.name}) {
this.${field.name} = ${field.name};
return this;
}
<% } %>
public ${cls.name} build() {
final ${cls.name} data = new ${cls.name}();
<% for(field in cls.fields) {%>
data.${field.setter.name}(this.${field.name});
<% } %>
return data;
}
}
It really depends on what you are trying to do. Code generation is a topic within itself. Without a specific use-case, I suggest looking at velocity code generation/template library. Also, if you are doing the code generation offline, I would suggest using something like ArgoUML to go from UML diagram/Object model to Java code.
Exemple :
1/
private JFieldVar generatedField;
2/
String className = "class name";
/* package name */
JPackage jp = jCodeModel._package("package name ");
/* class name */
JDefinedClass jclass = jp._class(className);
/* add comment */
JDocComment jDocComment = jclass.javadoc();
jDocComment.add("By AUTOMAT D.I.T tools : " + new Date() +" => " + className);
// génération des getter & setter & attribues
// create attribue
this.generatedField = jclass.field(JMod.PRIVATE, Integer.class)
, "attribue name ");
// getter
JMethod getter = jclass.method(JMod.PUBLIC, Integer.class)
, "attribue name ");
getter.body()._return(this.generatedField);
// setter
JMethod setter = jclass.method(JMod.PUBLIC, Integer.class)
,"attribue name ");
// create setter paramétre
JVar setParam = setter.param(getTypeDetailsForCodeModel(Integer.class,"param name");
// affectation ( this.param = setParam )
setter.body().assign(JExpr._this().ref(this.generatedField), setParam);
jCodeModel.build(new File("path c://javaSrc//"));
Here is a JSON-to-POJO project that looks interesting:
http://www.jsonschema2pojo.org/