Returning a GeoJSON object in java - java

I am new to GeoJSON and im currently running into an issue that I just don't know how to do it.
Here is a snippet of what my FeatureCollection looks like
FeatureCollection fc = new FeatureCollection();
Map<String, Object> properties = new HashMap<String, Object>();
for(int i = 0; i < platforms.size(); i ++) {
Feature feature = new Feature();
Point geometry = new Point();
Dto dto = platforms.get(i);
Position position = new Position(dto.getLat(), dto.getLon());
fc.addFeature(feature);
geometry.setCoordinates(position);
feature.setGeometry(geometry);
feature.setProperties(properties);
properties.put("name", dto.getName());
properties.put("msl", dto.getMsl());
properties.put("id", dto.getId());
}
return fc.toString();
I want my output to look like this:
{
"type":"FeatureCollection"
features":[
{
"type":"Feature"
"geometry": {
"type":"Point"
"coordinates":[
-120.200000,
10.100000
]
},
"properties": {
"name": "1"
"height": "100.00"
"id": "null"
}
}
{
"type":"Feature"
"geometry": {
"type":"Point"
"coordinates\":[
-130.200000,
20.100000
] \n "
}, \n "
"properties": { "
"name": "2"
"height": "100.00"
"id": "null"
}
}
]
}
As far as I can tell, through debugging, the correct information is being placed into the feature but whenever I return the featureCollection I get this:
mil.nga.sf.geojson.FeatureCollection#366ac49b
I don't know much about geojson but it seems like I'm incorrectly returning the FeatureCollection and its printing out its name or whatever.
Simply put, how do I print the contents of a FeatureCollection?
EDIT:
This is the output that I get after implementing gson.
{
"features": [
{
"feature": {
"geometry": {
"x": 10.1,
"y": -120.2,
"z": null,
"m": null,
"geometryType": "POINT",
"hasZ": false,
"hasM": false
},
"properties": {
"msl": 100.0,
"name": "1",
"id": null
}
},
"id": null,
"bbox": null,
"foreignMembers": {}
},
{
"feature": {
"geometry": {
"x": 20.1,
"y": -130.2,
"z": null,
"m": null,
"geometryType": "POINT",
"hasZ": false,
"hasM": false
},
"properties": {
"msl": 100.0,
"name": "2",
"id": null
}
},
"id": null,
"bbox": null,
"foreignMembers": {}
}
],
"bbox": null,
"foreignMembers": {}
I am unsure what to do moving forward to get this to mirror my desired output.

Your problem is that you're calling fc.toString();, which will hit the default Object.toString() method. This will dump some classname+address/id-like String, depending on th JVM used.
Instead of calling toString(), you should use a JSON library like google gson, and add
a few lines to the bottom of your code:
final GsonBuilder gb = new GsonBuilder();
gb.setPrettyPrinting();
gb.serializeNulls();
// gb.excludeFieldsWithoutExposeAnnotation(); // maybe use for more control
final Gson gson = gb.create();
final String jsonText = gson.toJson(fc);
return jsonText;
Also consider writing a utility class that does this for you with default settings that you choose:
public class MyJsonUtil {
static public String toJSON(final Object pObject) {
final GsonBuilder gb = new GsonBuilder();
gb.setPrettyPrinting();
gb.serializeNulls();
// gb.excludeFieldsWithoutExposeAnnotation(); // maybe use for more control
final Gson gson = gb.create();
final String jsonText = gson.toJson(pObject);
return jsonText;
}
}
and then at the end of your code you simply call return MyJsonUtil.toJSON(fc).

Related

Jackson JSON check values before adding them to list

Code snippet:
ObjectMapper objectMapper = new ObjectMapper();
try {
this.persons = objectMapper.readValue(new File(fileName),
new TypeReference<List<Person>>() {
});
} catch (IOException ex) {
}
Example json input:
[
{
"id": 1,
"name": "The Best",
"email": "thenextbigthing#gmail.com",
"birthDate": "1981-11-23"
},
{
"id": 2,
"name": "Andy Jr.",
"email": "usa#gmail.com",
"birthDate": "1982-12-01"
},
{
"id": 3,
"name": "JohnDoe",
"email": "gameover#gmail.com",
"birthDate": "1990-01-02"
},
{
"id": 4,
"name": "SomeOne",
"email": "rucksack#gmail.com",
"birthDate": "1988-01-22"
},
{
"id": 5,
"name": "Mr. Mxyzptlk",
"email": "bigman#hotmail.com",
"birthDate": "1977-08-12"
}
]
I'd like to know if it's possible (then how?) to check the values before creating an object and add it to the list. For example, i don't want the object being created and added to the list if the e-mail address or name is longer than 30 characters or if name matches certain regex expression etc. Instead I want to throw an IOException with something like "wrong input data". I'm not allowed to create more custom classes.
I believe you can't do this, because Jackson works on parsing, not for validation.
My suggestion:
public boolean checkJson(String jsonStr, Class<?> valueType) throws JsonParseException, IOException {
ObjectMapper mapper = new ObjectMapper();
try {
List<TypeHere> list = mapper.readValue(jsonStr, valueType);
return list.stream().anyMatch(s -> s.length() < 30);
} catch (JsonMappingException e) {
return false;
}
}
Instead return a boolean value, you can throw a Exception.
Obs: I'm working on my English yet. Please, feel free to edit.

The structure of my GeoJSON does not allow LeafLet to display the points on the layer

I am using the leaflet-ajax project (https://github.com/calvinmetcalf/leaflet-ajax) and I want to declare a geojsonLayer variable like this :
var geojsonLayer = L.geoJson.ajax("http://localhost:7070/findInArea");
where http://localhost:7070/findInArea is an endpoint to a Dropwizard REST web service that I coded.
Before trying to use http://localhost:7070/findInArea as a parameter I tried as parameter a JSON file containing what my REST web service returns :
{
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"properties": {
"imo": 0,
"course": "0.0",
"description": "description",
"mmsi": 432473000,
"type": "VESSEL",
"heading": "NaN"
},
"geometry": {
"type": "Point",
"coordinates": [-4.064533333333333, 5.29355]
}
}, {
"type": "Feature",
"properties": {
"imo": 0,
"course": "0.0",
"description": "description",
"mmsi": 375488000,
"type": "VESSEL",
"heading": "NaN"
},
"geometry": {
"type": "Point",
"coordinates": [-4.025521666666666, 5.303138333333333]
}
}, {
"type": "Feature",
"properties": {
"imo": 0,
"course": "0.0",
"description": "description",
"mmsi": 355794000,
"type": "VESSEL",
"heading": "NaN"
},
"geometry": {
"type": "Point",
"coordinates": [-4.01319, 5.28968]
}
}]
}
When I try with this JSON the points are not displayed on the layer. I searched on the Web an example of (Geo)JSON for which it works. On https://github.com/calvinmetcalf/leaflet-ajax/tree/gh-pages/example I found one which is :
{
"type":"FeatureCollection",
"features":[
{
"geometry":{
"type":"Point",
"coordinates":[
-71.123723098996251,
42.379003083976961
]
},
"type":"Feature",
"id":0,
"properties":{
"UNDERGRAD":43,
"CITYST":"Cambridge, MA",
"OBJECTID":72.0,
"URL":"http://www.longy.edu",
"TYPE":"PRI",
"DESCRIPTN":"4-year or above",
"NCES_ID":"166489",
"ZIPCODE":"02138",
"L_ACC_EST":16,
"SITE":"1",
"L_SRC_1":"nces.ed.gov",
"L_BASE":"DOQ",
"DEGREES":"C, M",
"L_TYPE":"CB",
"ADDRESS":"One Follen St",
"COLLEGE":"Longy School Of Music",
"L_METH":"IN-WEBSITE",
"GRAD":137,
"MAIN_TEL":"(617) 876-0956"
}
},
{
"geometry":{
"type":"Point",
"coordinates":[
-71.308156671517793,
42.643612284195882
]
},
"type":"Feature",
"id":1,
"properties":{
"UNDERGRAD":79,
"CITYST":"Lowell, MA",
"OBJECTID":73.0,
"URL":"http://www.lowellacademy.com",
"TYPE":"PRI",
"DESCRIPTN":"less-than-2-year",
"NCES_ID":"166498",
"ZIPCODE":"01852",
"L_ACC_EST":16,
"SITE":"1",
"L_SRC_1":"nces.ed.gov",
"L_BASE":"DOQ",
"DEGREES":"C",
"L_TYPE":"CB",
"ADDRESS":"136 Central St",
"COLLEGE":"Lowell Academy Of Hairdressing",
"L_METH":"IN-VERB",
"GRAD":0,
"MAIN_TEL":"(978) 453-3235"
}
}
]
}
Currently the Java code of my REST web service is :
#Override
public FeatureCollection findTracksInACertainArea(double longitudeMin, double longitudeMax, double latitudeMin, double latitudeMax){
FeatureCollection fc = new FeatureCollection();
List<Feature> features = new ArrayList<Feature>();
DBCursor cursor = null;
BasicDBObject query = new BasicDBObject();
query.put("detection.position.0", BasicDBObjectBuilder.start("$gte", longitudeMin).add("$lte", longitudeMax).get());
query.put("detection.position.1", BasicDBObjectBuilder.start("$gte", latitudeMin).add("$lte", latitudeMax).get());
cursor = collection.find(query);
while(cursor.hasNext()) {
final Track track = TrackDAOHelper.convertTrackFromDBObject(cursor.next());
features.add(buildFeature(track));
}
fc.setFeatures(features);
return fc;
}
private Feature buildFeature(Track track) {
Feature feature = new Feature();
Point point = new Point(track.getDetection().getPosition().getLongitude(), track.getDetection().getPosition().getLatitude());
feature.setGeometry(point);
Map<String, Object> properties = buildProperties(track);
feature.setProperties(properties);
return feature;
}
private Map<String, Object> buildProperties(Track track) {
Map<String, Object> properties = new HashMap<String, Object>();
if (track != null) {
if (track.getName() != null)
properties.put("name", track.getName());
properties.put("course", "0.0");
properties.put("heading", "NaN");
properties.put("type", "VESSEL");
if (track.getMmsi() != null)
properties.put("mmsi", track.getMmsi());
if (track.getImo() != null)
properties.put("imo", track.getImo());
if (track.getCallsign() != null)
properties.put("callsign", track.getCallsign());
String description = buildDescription();
properties.put("description", description);
}
return properties;
}
private String buildDescription() {
return "description";
}
How can I modify it in order to get a working (Geo)JSON?
It is not due to the JSON, it is due to the around Javascript code

Deserializing json that is false or object with Retrofit GsonConverterFactory

I am working with a server that returns json. One of the elements is either an object or false - it it is non exiting. I know this is very poor implementation of server response and there are quite a few such cases, but this is what I have to work with. How can I deal with this situation? If there is an object I successfully deserialze it, if none - i get error - EXPECTED OBJECT FOUND BOOLEAN.
Even worse, I do not know where I am gonna meet such situations in future on this project.
This is the sample json:
{
"course": {
"id": "47902",
"course": "3844",
"group": "1825",
"teacher": "59502",
"table": "1447",
"client": "1",
"course_id": "3844",
"description": ""
},
"teacher": {
"id": "59502",
"post": "0",
"experience": "",
"dep_experience": "",
"rank": "0",
"online": "1458891283",
"departments": [
null
]
},
"depart": {
"id": "100",
"postcode": "",
"public": "1",
"alias": "",
"faculty": "97",
"client": "1"
},
"progress": false,
"files": [
{
"teacher": {
"id": "59502",
"code": "53bd7c21ad05b03e",
"photo": "1"
},
"files": [
{
"id": "0ffe41e5003ee5c0",
"owner": "59502",
"address": "0ffe41e5003ee5c0",
"type": "f",
"size": "0",
"time": "2015-07-10 14:39:15",
"data": ""
}
]
}
]
}
As you can see progress is false here. Other times it is ordinary object like depart. Deserialization is done by Retrofit 2.
Thanks a lot.
I'm assuming you have a top-level mapping similar to the following one and have configured your Retrofit instance for Gson:
final class Response {
#SerializedName("progress")
#JsonAdapter(FalseAsNullTypeAdapterFactory.class)
final Progress progress = null;
}
final class Progress {
final String foo = null;
}
Note that the progress property is annotated with the #JsonAdapter annotation: we're assuming this is only place were the progress property can be a boolean (if you have many places like this one, you can either annotate each field with this annotation, or .registerTypeAdapter() via GsonBuilder; in case of .registerTypeAdapterFactory() the factory must check against known types in order not to "intercept" all types).
Now, here is a type adapter factory to deal with your issue:
final class FalseAsNullTypeAdapterFactory
implements TypeAdapterFactory {
// Let Gson instantiate it itself
private FalseAsNullTypeAdapterFactory() {
}
#Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
// Get a downstream parser (for simplicity: get the default parser for the given type)
final TypeAdapter<T> delegateTypeAdapter = gson.getDelegateAdapter(this, typeToken);
return new TypeAdapter<T>() {
#Override
public void write(final JsonWriter out, final T value) {
throw new UnsupportedOperationException();
}
#Override
public T read(final JsonReader in)
throws IOException {
// Peek whether the next JSON token is a boolean
if ( in.peek() == BOOLEAN ) {
// And take the this JSON token as a boolean value
// Is it true?
if ( in.nextBoolean() ) {
// Then it's not something we can handle -- probably a boolean field annotated with #JsonAdapter(FalseAsNullTypeAdapterFactory.class)?
throw new MalformedJsonException("Unexpected boolean marker: true");
}
// We're assuming it's null
return null;
}
// If it's not a boolean value, then we just delegate parsing to the original type adapter
return delegateTypeAdapter.read(in);
}
};
}
}
Now just test it:
try ( final Reader reader = getPackageResourceReader(Q43231983.class, "success.json") ) {
final Response response = gson.fromJson(reader, Response.class);
System.out.println(response.progress.foo);
}
try ( final Reader reader = getPackageResourceReader(Q43231983.class, "failure.json") ) {
final Response response = gson.fromJson(reader, Response.class);
System.out.println(response.progress);
}
where the given resources are:
success.json is {"progress":{"foo": "bar"}};
failure.json is {"progress":false}.
The output is as follows:
bar
null

Print an Arraylist to RESTful webservices

first of all, my question would be a bit long but i dont think its complex. But i simply have not clue where the problem could be.
So let me start.
Im trying to print an Arraylist into webpages. I have a json file like this:
[
{
"id": 0,
"brand": "audi",
"model": "q8",
"color": "red",
"price": "123",
"available": false
},
{
"id": 1,
"brand": "audi",
"model": "r6",
"color": "sfg",
"price": "952",
"available": true
},
{
"id": 2,
"brand": "BMW",
"model": "IDK",
"color": "Red",
"price": "105",
"available": true
}
]
I read the json file and save the data into an arraylist "carList" with this method
try(JsonReader jsonReader = new JsonReader(new InputStreamReader(new FileInputStream(this.db)))){
Gson myGson = new Gson();
JsonParser jsonParser = new JsonParser();
JsonArray array = jsonParser.parse(jsonReader).getAsJsonArray();
this.carList = new ArrayList<Car>();
for (JsonElement element : array) {
Car car = myGson.fromJson(element, Car.class);
carList.add(car);
}
}catch(IOException e){
e.printStackTrace();
}
My "Car" class has those variables
private int id = 0;
private String brand;
private String model;
private String color;
private String price;
private boolean available = true;
And when i print my "carList" with this
public ArrayList<Car> printAllCars(){
return carList;
}
and this
#RequestMapping(value = "/cars", method = RequestMethod.GET)
#ResponseBody
ArrayList<Car> printAllCars() {
return cars.printAllCars();
}
I got this with postman
postman result
So as you can see, the problem is the price is not printed and "available" is printed as "state".
But when i print in eclipse the price is displayed.
eclipse result
Sorry for my long post, my bad english and my bad code but please help me guys !
Jackson looks at get...() and set...() methods, so don't forget to add these methods or us filed-based serialization.

How to get json value using GSON from json tree

I have a json such as below
{
"apiVersion": "v1",
"metadata": {
"status": {
"statusCode": 0
},
},
"stuff": [
{
"name": {
"text": "red"
},
"properties": [
{
"attributes": {
"shade": "dark"
},
"component": {
"id": "BA1",
}
"type": "Color"
}
]
},
{
"name": {
"text": "Toyota Camry"
},
"properties": [
{
"attributes": {},
"component": {
"id": "MS",
},
"type": "Vehicle"
}
]
},
]
}
I'm using GSON to parse the results like this:
Gson gson = new Gson();
JsonObject json = (JsonObject) gson.fromJson(in, JsonObject.class);
System.out.println(json.get("apiVersion").getAsString());
I can get the apiVersion but don't know how to get elements that are inside the json tree. For example, type...what if I want to output all the different type..in this case Color and Vehicle
I must be missing something here, but why can't you nest calls to getJsonObject? For example, to get the status code:
System.out.println(json.getAsJsonObject("metadata")
.getAsJsonObject("status")
.get("statusCode").getAsInt());
You can create an object in that matter and to parse the json to it (with GSON):
ParsedObject parsedObject = new Gson().fromJson(json, ParsedObject.class);
public class ParsedObject {
#SerializedName(value = "apiVersion")
private String mApiVersion;
#SerializedName(value = "metadata")
private Metadata mMetadata;
}

Categories

Resources