I declared a custom class in my project:
public class LocationData {
private Location location;
private LocalDateTime localDateTime;
private int heartRate;
private int calories;
private int ropeMoves;
private int dumbbellMoves;
private int pedalRotations;
private int wheelRotations;
private int numberOfSteps;
public LocationData(Location location, LocalDateTime localDateTime, int heartRate, int calories, int ropeMoves, int dumbbellMoves, int pedalRotation, int wheelRotations, int numberOfSteps) {
this.location = location;
this.localDateTime = localDateTime;
this.heartRate = heartRate;
this.calories = calories;
this.ropeMoves = ropeMoves;
this.dumbbellMoves = dumbbellMoves;
this.pedalRotations = pedalRotations;
this.wheelRotations = wheelRotations;
this.numberOfSteps = numberOfSteps;
}
public Location getLocation() {
return location;
}
public LocalDateTime getLocalDateTime() {
return localDateTime;
}
// Other getters
#Override
public String toString() {
return "LocationData[" +
"\n\tlocation=" + location +
"\n\tlocalDateTime=" + localDateTime +
"\n\tcalories=" + calories +
"\n\theartRate=" + heartRate +
"\n\tropeMoves=" + ropeMoves +
"\n\tdumbbellMoves=" + dumbbellMoves +
"\n\tpedalRotations=" + pedalRotations +
"\n\twheelRotations=" + wheelRotations +
"\n\tnumberOfSteps=" + numberOfSteps +
"]";
}
}
It represents a location plus some infos. Then I save a List of LocationData to create a "route".
I need to save this List (called location) to a file because the user, in the future, will ask to retrieve it to create a GPX file.
I think that the best solution is make the LocationData class serializable, but I don't know how to serialize (then deserialize) it. So... I need to understand how:
Serialize LocationData class
Deserialize LocationData class
Create a List of serialized LocationData
Write the list in a file
Read the list from a file
You need to add implements Serializable to the class definition, but you don't have to implement Serializable's methods - Object already has a default implementation, and the Serializable interface is used as a declarative.
You also need to ensure that Location and LocalDateTime are both Serializable.
Finally, once that's all in place you can use ObjectInputStream / ObjectOutputStream to read and write your objects
Related
Below is my JSON:
{
"time":{
"date":{
"year":2017,
"month":3,
"day":12
},
"time":{
"hour":10,
"minute":42,
"second":42,
"nano":810000000
}
},
"name":"Jon",
"message":{
"product":"orange"
"price":2000
}
}
'time' field has a nested 'time' field. How can I parse this using jackson to java object. Can anyone please tell me the correct method?
You can create classes like these:
class JavaObject {
private TimeObject time;
private String name;
//other fields
//getters and setters
}
class TimeObject {
private Date date;
private Time time;
//getters and setters
}
class Date {
private int year;
private int month;
private int day;
//getters and setters
}
class Time {
private int hour;
private int minute;
private int second;
private long nano;
//getters and setters
}
Once done, you can use Jackson to deserialize the json String into JavaObject object, e.g.:
ObjectMapper objectMapper = new ObjectMapper();
JavaObject javaObject = objectMapper.readValue("{\n" +
" \"time\":{\n" +
" \"date\":{\n" +
" \"year\":2017,\n" +
" \"month\":3,\n" +
" \"day\":12\n" +
" },\n" +
" \"time\":{\n" +
" \"hour\":10,\n" +
" \"minute\":42,\n" +
" \"second\":42,\n" +
" \"nano\":810000000\n" +
" }\n" +
" },\n" +
"\"name\":\"Jon\"}", JavaObject.class);
System.out.println(javaObject);
If you only need the inner time object, you could do this in a quick way:
// your POJO class
// (public fields sould be private with getter & setter, of course)
public class Pojo {
public int hour;
public int minute;
public int second;
public long nano;
#Override
public String toString() {
return hour + ":" + minute + ":" + second + ":" + nano;
}
}
And then:
//your json string
String jsonString = "{\"time\":{\"date\":{\"year\":2017,\"month\":3,\"day\":12},"
+ "\"time\":{\"hour\":10,\"minute\":42,\"second\":42,\"nano\":810000000}},"
+ "\"name\":\"Jon\",\"message\":{\"product\":\"orange\",\"price\":2000}}";
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonRoot = mapper.readTree(jsonString); //parse string to JsonNode
Pojo pojo = mapper.treeToValue(jsonRoot.at("/time/time"), Pojo.class); //create Pojo instance from inner time object
System.out.println(pojo); //see if it worked
This prints:
10:42:42:810000000
Use Jackson library
ObjectMapper jsonMapper= new ObjectMapper();
YourCorrespondingObject object = jsonMapper.readValue("your json as string...", YourCorrespondingObject.class);
it's easier first to build your object, populate it, and convert to string, to make sure it equals your existing string, like:
String jsonInString = mapper.writeValueAsString(object);
I have list:
private List<Day> days = new ArrayList<>();
My Day object:
public class Day implements Identifiable {
private Integer id;
private byte isHoliday;
//getters and setters
}
I added a new Day object like:
Day day = new Day();
day.setHoliday(1);
days.add(day);
How to make, that at adding of a new element, field id set automatically, which equal to the previous element + 1?
Maybe I can use Java 8 Streams?
You can use AtomicInteger() - it is thread safe.
public class Day implements Identifiable {
private static AtomicInteger count = new AtomicInteger(0);
private int id;
private byte isHoliday;
public Day() {
this.id = count.incrementAndGet();
}
}
You could use a static member and a constructor:
public class Day implements Identifiable {
static private int maxId = 0;
final private Integer id;
private byte isHoliday;
public Day() {
this.id = maxId;
maxId++;
}
}
Every time you create a new instance of Day its id member is set to the value of maxId and then maxId is incremented.
Making "id" final is a good idea since it is used to identify your object.
Use a static variable say oldId to store the previous id. Change your Day class to:
public class Day implements Identifiable {
private static Integer oldId = 0;
private Integer id;
private byte isHoliday;
public Day() {
this.id = oldId + 1;
oldId++;
}
//getters and setters
}
If you can try to use simple types rather than object-oriented ones, i.e. instead of Integer to int.
public class Day {
private static int serial = 0; //static means that this is a common field (the same place in memory) for all created objects.
private final int id; //final means that another value / object can not be assigned to this reference after initializing in the constructor.
public Day() {
id = serial++;
}
//getters and setters
}
I have an object that is a list of 'Level' objects and I'm testing transferring them with Spring Boot Rest Controller in 2 ways:
with JSON, in Rest Controller I use something like:
#RequestMapping(value = "/api/v1/layers/{layername}", method = RequestMethod.GET, produces = "application/json")
public #ResponseBody List<Level> query(#PathVariable String layername,
#RequestParam("northEastLat") Float northEastLat,
#RequestParam("northEastLng") Float northEastLng,
#RequestParam("northWestLat") Float northWestLat,
#RequestParam("northWestLng") Float northWestLng,
#RequestParam("southEastLat") Float southEastLat,
#RequestParam("southEastLng") Float southEastLng,
#RequestParam("southWestLat") Float southWestLat,
#RequestParam("southWestLng") Float southWestLng
) {
List<Level> poligons=levelService.obtainLevels(layername,southWestLng,southWestLat,northWestLng,northWestLat,northEastLng,northEastLat,southEastLng,southEastLat);
int i=1;
for (Level p : poligons) {
System.out.println("poligon" + i++ + " is:" + p.toString());
}
return poligons;
}
With Protostuff Protobuf format, I use something like:
#RequestMapping(value = "/api/v1/layers/{layername}", method = RequestMethod.GET,produces = "text/plain")
public String query(#PathVariable String layername,
#RequestParam("northEastLat") Float northEastLat,
#RequestParam("northEastLng") Float northEastLng,
#RequestParam("northWestLat") Float northWestLat,
#RequestParam("northWestLng") Float northWestLng,
#RequestParam("southEastLat") Float southEastLat,
#RequestParam("southEastLng") Float southEastLng,
#RequestParam("southWestLat") Float southWestLat,
#RequestParam("southWestLng") Float southWestLng
) {
List<Level> poligons=levelService.obtainLevels(layername,southWestLng,southWestLat,northWestLng,northWestLat,northEastLng,northEastLat,southEastLng,southEastLat);
LevelList list = new LevelList(poligons);
byte[] bytes;
int i=1;
for (Level p : poligons) {
System.out.println("poligon" + i++ + " is:" + p.toString());
}
Schema<LevelList> schema = RuntimeSchema.getSchema(LevelList.class);
LinkedBuffer buffer = LinkedBuffer.allocate();
try
{
bytes = ProtostuffIOUtil.toByteArray(list, schema, buffer);
}
finally
{
buffer.clear();
}
return new String(bytes);
}
The Level object format is :
[{"wkb_geometry":"{"type":"Polygon","coordinates":[[[24.446822,45.34997],[24.706508,45.352485]]]}","id":199,"level":"3","type":null}
The Level object is :
#Entity(name = "Level")
#Table(name="Level2G")
#SecondaryTables({
#SecondaryTable(name="Level3G"),
#SecondaryTable(name="Level4G")
})
public class Level implements Serializable {
private static final long serialVersionUID = 1L;
// #Column(name = "wkb_geometry",columnDefinition="Geometry")
//#Type(type = "org.hibernate.spatial.GeometryType")
#Column(name="wkb_geometry")
private /*Geometry */ String wkb_geometry;
#Id
#Column(name="id")
private Integer id;
#Column(name="level")
private String level;
#Transient
private String type;
public Level() {
}
public Level(String wkb_geometry, Integer id, String level) {
this.wkb_geometry = wkb_geometry;
this.id = id;
this.level = level;
this.type = "Feature";
}
public Level(String wkb_geometry, Integer id, String level, String type) {
this.wkb_geometry = wkb_geometry;
this.id = id;
this.level = level;
this.type = type;
}
public Object getWkb_geometry() {
return wkb_geometry;
}
public void setWkb_geometry(String wkb_geometry) {
this.wkb_geometry = wkb_geometry;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getLevel() {
return level;
}
public void setLevel(String level) {
this.level = level;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
#Override
public String toString() {
return "Level{" +
"wkb_geometry=" + wkb_geometry +
", id=" + id +
", level='" + level + '\'' +
", type='" + type + '\'' +
'}';
}
}
The LevelList object is just a List of Level objects
The problem is that with Protostuff I get a bigger payload (26 kb) comparing to JSON (3.7kb). Why?
Also for second option I also tried setting "application/octet-stream" to return bytes directly but still the same result. Also I compared speed for both JSON and protobuf; protobuf has the better performance even with a bigger payload. Any idea why?
Protostuff and Protobuf are not the same thing. Protostuff is a wrapper library that can use many different serialization formats. It also supports runtime schema generation, which you appear to be using. That runtime schema requires sending extra metadata along with the message to tell the receiver about the message's schema. I would guess that the large message you're seeing is mostly from this runtime schema data.
With standard Protobuf, the schema is not sent with the message because it is assumed that the sender and recipient already agree on a schema provided by a .proto file compiled into both programs. If you use Protobuf with a standard .proto file, you'll find that the messages it produces are much smaller than JSON.
You have at least one problem in your test.
This transformation from byte array to String is not valid:
bytes = ProtostuffIOUtil.toByteArray(list, schema, buffer);
return new String(bytes);
This constructor of String will try to parse byte array as a UTF-8 string (most probably; depends on your locale settings), but given data by definition is not valid UTF-8 string.
If you want to make better size comparison, you should write a test in a following form:
LevelList source = testData();
byte[] jsonData = generateJson(source);
byte[] protobufData = generateProtobuf(source);
System.out.println("JSON=" + jsonData.size() + " Protobuf=" + protobufData.size());
Main point here is to make your test reproducible, so that other people can repeat it.
I have a POJO class:
#Entity
#Table(name = "interruttori", catalog = "SMARTPARK")
public class Interruttore implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private int idInterruttore;
private int numeroInterruttore;
private String nomeInterruttore;
private String descrizione;
private List<Luce> luci;
private String pinName;
private boolean remoto;
private boolean stato;
private Date dateTime;
private Set<Integer> activeSensors = new HashSet<Integer>();
//getters and setters and specifically
#Transient
public Set<Integer> getActiveSensors() {
return activeSensors;
}
public void setActiveSensors(Set<Integer> activeSensors) {
this.activeSensors = activeSensors;
}
It's #Transient because I don't want to persist the Set, i need it just as a "counter" in a Controller.
The controller part we need is:
#RequestMapping(value="/sensoristica")
public ResponseEntity<Sensoristica> findIlluminazione(#RequestParam(value="idLuce") int idLuce,
#RequestParam(value="lit") boolean lit,
#RequestParam(value="suServer") boolean suServer) {
Sensoristica sensoristica = new Sensoristica();
Luce luce = luceService.findById(idLuce);
String nomeLuce = luce.getNomeLuce();
int numeroLuce = luce.getNumeroLuce();
sensoristica.setLuce(luce);
sensoristica.setLit(lit);
sensoristicaService.saveSensoristica(sensoristica);
logger.debug("Aggiornato sensore " + numeroLuce + " ("+nomeLuce+") acceso: "+lit);
//aggiorniamo lo stato del sensore
luce.setLit(lit);
luceService.updateLuce(luce);
//qui gestisco l'interruttore
if(suServer){
int idInterruttore = luce.getInterruttore().getIdInterruttore();
Interruttore interruttore = interruttoreService.findById(idInterruttore);
Set<Integer> activeSensors = interruttore.getActiveSensors();
logger.debug("Active sensor è " +activeSensors);
if(lit){
activeSensors.add(idLuce);
logger.debug("Aggiungo id "+idLuce);
logger.debug("Active è lungo: "+activeSensors.size());
} else {
if (activeSensors.contains(idLuce)){
activeSensors.remove(idLuce);
logger.debug("Rimuovo id "+idLuce);
logger.debug("Active è lungo: "+activeSensors.size());
}
}
interruttore.setActiveSensors(activeSensors);
interruttoreService.updateInterruttore(interruttore);
boolean canShutDown = activeSensors.isEmpty();
logger.debug("canShutDown is "+canShutDown);
Basically, I want to add or remove idLuceto the Set and then check if activeSensors.isEmpty().
The problem is that every call to the Controller gives me back an empty Set, not a Set with the previous idLuces inside.
How can I obtain it?
Actually #Transient should be applied according to AccessType.
Please try setting #Transient to the field.
#Transient
private Set<Integer> activeSensors = new HashSet<Integer>();
I am developing an application using GeoModel. I need to perform search in a particular radius based on the given latitude and longitude. I am able to generate the GeoCells in the datastore using Objectify, but not able to get back the results in a particular radius.
I am sharing my code below.
Entity Class
#Entity
public class NewsFeed implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Index
private Long feedID;
#Index
private String topic;
#Index
private String title;
private String description;
#Index
private Date createDate;
private String imageOrVideo;
private String imageUrl;
private String blobKey;
#Latitude
private Double latitude;
#Longitude
private Double longitude;
#Geocells
private List<String> cells;
// getter and setters ...
}
Custom GeocellQueryEngine Class From This Source
public class ObjectifyGeocellQueryEngine implements GeocellQueryEngine {
private String geocellsProperty;
private Objectify ofy;
public static final String DEFAULT_GEOCELLS_PROPERTY = "cells";
public ObjectifyGeocellQueryEngine(Objectify ofy) {
this(ofy, DEFAULT_GEOCELLS_PROPERTY);
}
public ObjectifyGeocellQueryEngine(Objectify ofy, String geocellsProperty) {
this.ofy = ofy;
this.geocellsProperty = geocellsProperty;
}
#Override
public <T> List<T> query(GeocellQuery baseQuery, List<String> geocells, Class<T> entityClass) {
StringTokenizer st;
int tokenNo = 0;
Query<T> query = ofy.query(entityClass);
if (baseQuery != null) {
st = new StringTokenizer(baseQuery.getBaseQuery(), ",");
while (st.hasMoreTokens()) {
query.filter(st.nextToken(), baseQuery.getParameters().get(tokenNo++));
}
}
return query.filter(geocellsProperty + " IN", geocells).list();
}
}
Fetching Data Here
Point p = new Point(24.8993714, 79.5839124);
// Generates the list of GeoCells
List<String> cells = GeocellManager.generateGeoCell(p);
List<Object> params = new ArrayList<Object>();
params.add("Movies");
GeocellQuery baseQuery = new GeocellQuery("topic == topic", "String topic",params);
ObjectifyGeocellQueryEngine objectifyGeocellQueryEngine = new ObjectifyGeocellQueryEngine(ofy(), "cells");
List<NewsFeed> list = objectifyGeocellQueryEngine.query(baseQuery, cells, NewsFeed.class);
List<NewsFeed> list2 = GeocellManager.proximitySearch(p, 10, 10000,NewsFeed.class, baseQuery, objectifyGeocellQueryEngine, GeocellManager.MAX_GEOCELL_RESOLUTION);
System.out.println(list+" : "+list2);
Now the problem is I am not getting any results out from here. Can you people please help me with this as I am not getting any exception, just getting the empty list.
I have done a workaround for this situation I have added a parallel JDO Class to store and retrieve the geospatial results.