I'm new to the thrift. I need to convert my data object to a JSON string with Thrift JSON serialization.
I tried in this way.
TSerializer serializer = new TSerializer(new TSimpleJSONProtocol.Factory());
String json = serializer.toString(object_name);
In here is an error, that object_name should be in TBase. How can I resolve this ?
In here is an error, that object_name should be in TBase.
Next time, please post the exact error message (use copy+paste), this makes it easier for all of us.
How can I resolve this?
Whatever you want to serialize with Thrift, must be an descendant of Thrift's TBase class. You achieve this by writing some Thrift IDL and save it as a file (e.g. MyDataStructs.thrift):
struct Employee {
1: string name
2: string surname
3: i32 age
}
Next, you pass that file to the Thrift compiler and tell him to generate some C# code from it:
thrift -gen csharp MyDataStructs.thrift
This gives you a class derived from TBase:
public partial class Employee : TBase
{
private string _name;
private string _surname;
private int _age;
// properties
public string Name {... }
public string Surname { ... }
public int Age { ... }
// some details omitted
public void Read (TProtocol iprot)
{
// generated code for Read() method
}
public void Write(TProtocol oprot) {
// generated code for Write() method
}
public override string ToString() {
// generated code for ToString() method
}
}
This is what Thrift expects.
If below is what your are doing then it should work. Check if you are doing this. Employee is a demo call here, you have to use your actual class.
Employee object_name= new Employee();
object_name.setAge(27);
object_name.setName("Test");
TSerializer serializer = new TSerializer(new TSimpleJSONProtocol.Factory());
String json = serializer.toString(object_name);
Related
i try to use some web api, so i do this
public static void main(String[] args) {
// Create Jersey client
Client client = Client.create();
// GET request to findBook resource with a query parameter
String getSoccersSeasonsUrl = "http://api.football-data.org/v1/soccerseasons";
WebResource webResourceGet = client.resource(getSoccersSeasonsUrl);
webResourceGet.header("X-Auth-Token", myToken);
ClientResponse response = webResourceGet.get(ClientResponse.class);
String output = response.getEntity(String.class);
System.out.println(output);
}
output
[{"_links":{"self":{"href":"http://api.football-data.org/v1/soccerseasons/394"},"teams":{"href":"http://api.football-data.org/v1/soccerseasons/394/teams"},"fixtures":{"href":"http://api.football-data.org/v1/soccerseasons/394/fixtures"},
"leagueTable":{"href":"http://api.football-data.org/v1/soccerseasons/394/leagueTable"}},
"id":394,
"caption":"1. Bundesliga 2015/16",
"league":"BL1",
"year":"2015",
"currentMatchday":24,
"numberOfMatchdays":34,
"numberOfTeams":18,
"numberOfGames":306,
"lastUpdated":"2016-03-01T20:50:44Z ยป}
how can i fill from this output directly in a java ArrayList of object like:
public class SoccerSeason {
public SoccerSeason() {
}
private long id;
private String caption;
private String league;
private String year;
private long currentMatchday;
private long numberOfMatchdays;
private long numberOfTeams;
private long numberOfGames;
private String lastUpdated;
}
when i try to get directly SoccerSeason output = response.getEntity(SoccerSeason.class); i have a classic com.sun.jersey.api.client.ClientHandlerException
what's missing in my code please? do you have any idea how to do this simply?
What you want is Google's GSON. It can be found with a quick google search, and it has a ton of easy to read documentation.
Add GSON to your projects dependencies/source code, add getters and setters for all of your class members to the class you've created and it should work beautifully.
It is used like this:
Gson gson = new Gson();
SoccerSeason newSoccerSeason = gson.fromJson(webApiResponse, SoccerSeason.class);
String lastUpdated = newSoccerSeason.getLastUpdated();
Where webApiResponse is a String representation of the JSON received as your web API's response. You can also define a class SoccerSeasonList which looks like this:
public class SoccerSeasonList {
ArrayList<SoccerSeason> seasonList;
// getters/setters
}
Of course, your incoming JSON would have to have an object called seasonList containing all of your SoccerSeason objects to match up with this definition.
But then, you could grab your list like so:
SoccerSeasonList seasonList = gson.fromJson(webApiResponse, SoccerSeasonList.class);
ArrayList<SoccerSeason> seasonArr = seasonList.getSeasonList();
And perform operations like so:
for(SoccerSeason ss : seasonArr)
System.out.println(ss.getNumberOfMatchdays());
To recap: You simply match up your JSON object names and literals to their equivalent java types in a class, and call fromJSON on a String containing the JSON received from your web API that you'd like to parse, passing in the class you want the object parsed to.
What steps will reproduce the problem?
1.I have a json reponse as
String Content =
"{
"region":{
"state.code":"TX",
"country-code":"USA"
}
}";
2.I want to convert this Json Object into Java Object.I have this Java class to convert
public class Region{
private String stateCode;
private String countryCode;
public String getStateCode ()
{
return stateCode;
}
public void setStateCode (String stateCode)
{
this.stateCode = stateCode;
}
public String getCountryCode ()
{
return countryCode;
}
public void setCountryCode (String countryCode)
{
this.countryCode = countryCode;
}
}
3.My problem is Java doesnt allow . or - in variable name.Which doesnt allow json string to map to Region java class object giving null .
gson.fromJson(Content, Region.class);
What is the expected output? What do you see instead?
Can anybody please help me in this?
I have tried #SerializedName annotations but it is not working.
What version of the product are you using? On what operating system?
Please provide any additional information below.
You're trying to map this JSON
{
"region":{
"state.code":"TX",
"country-code":"USA"
}
}
to an instance of type Region. That JSON is a JSON Object which contains a pair with name region and a value which is a JSON Object. That JSON Object has two pairs, one with name state.code and JSON String value TX and one with name country-code and JSON String value USA.
You can't map that to a Region object. You have to bypass the root's pair named region.
Create a encapsulating type
class RegionContainer {
private Region region;
// the rest
}
and map that
gson.fromJson(Content, RegionContainer.class);
#SerializedName will work for your fields.
#SerializedName("state.code")
private String stateCode;
I am trying to deserialize a json string to POJO and then serialize it back to json string using Jackson, but in this process I want resultant json string to have changed key values.
e.g. input json string:
{"some_key":"value"}
here is what my POJO looks like
public class Sample {
#JsonProperty("some_key")
private String someKey;
public String getSomeKey(){
return someKey ;
};
}
When I serialize it again I want json string to be something like this
{"someKey":"value"} .
Is there any way I can achieve this?
I was able to do deserialization by renaming setter functions according to what is the input json string .
class Test{
private String someKey;
// for deserializing from field "some_key"
public void setSome_key( String someKey) {
this.someKey = someKey;
}
public String getSomeKey(){
return someKey;
}
}
You should be able to pull this off by defining a creator for deserialization and then let Jackson do its default behavior for serialization.
public class Sample {
private final String someKey;
#JsonCreator
public Sample(#JsonProperty("some_key") String someKey) {
this.someKey = someKey;
}
// Should serialize as "someKey" by default
public String getSomeKey(){
return someKey;
}
}
You may need to disable MapperFeature.AUTO_DETECT_CREATORS on your ObjectMapper for this to work.
My basic question: is there anything built that already does this automatically (doesn't have to be part of a popular library/package)? The main things I'm working with are Spring (MVC) and Jackson2.
I understand there are a few manual ways to do this:
Create a method in each class that serializes its specific properties into property=value& form (kind of stinks because it's a bunch of logic duplication, I feel).
Create a function that accepts an object, and uses reflection to dynamically read all the properties (I guess the getters), and build the string by getting each. I'm assuming this is how Jackson works for serialization/deserialization in general, but I really don't know.
Use some feature of Jackson to customly serialize the object. I've researched custom serializers, but it seems they are specific to a class (so I'd have to create one for each Class I'm trying to serialize), while I was hoping for a generic way. I'm just having trouble understanding how to apply one universally to objects. A few of the links:
http://techtraits.com/Programming/2011/11/20/using-custom-serializers-with-jackson/
http://wiki.fasterxml.com/JacksonHowToCustomSerializers
Use ObjectMapper.convertValue(object, HashMap.class);, iterate over the HashMap's key/value pairs, and build the string (which is what I'm using now, but I feel the conversions are excessive?).
I'm guessing there's others I'm not thinking of.
The main post I've looked into is Java: Getting the properties of a class to construct a string representation
My point is that I have several classes that I want to be able to serialize without having to specify something specific for each. That's why I'm thinking a function using reflection (#2 above) is the only way to handle this (if I have to do it manually).
If it helps, an example of what I mean is with, say, these two classes:
public class C1 {
private String C1prop1;
private String C1prop2;
private String C1prop3;
// Getters and setters for the 3 properties
}
public class C2 {
private String C2prop1;
private String C2prop2;
private String C2prop3;
// Getters and setters for the 3 properties
}
(no, the properties names and conventions are not what my actual app is using, it's just an example)
The results of serializing would be C1prop1=value&C1prop2=value&C1prop3=value and C2prop1=value&C2prop2=value&C2prop3=value, but there's only one place that defines how the serialization happens (already defined somewhere, or created manually by me).
So my idea is that I will have to end up using a form of the following (taken from the post I linked above):
public String toString() {
StringBuilder sb = new StringBuilder();
try {
Class c = Class.forName(this.getClass().getName());
Method m[] = c.getDeclaredMethods();
Object oo;
for (int i = 0; i < m.length; i++)
if (m[i].getName().startsWith("get")) {
oo = m[i].invoke(this, null);
sb.append(m[i].getName().substring(3) + ":"
+ String.valueOf(oo) + "\n");
}
} catch (Throwable e) {
System.err.println(e);
}
return sb.toString();
}
And modify it to accept an object, and change the format of the items appended to the StringBuilder. That works for me, I don't need help modifying this now.
So again, my main question is if there's something that already handles this (potentially simple) serialization instead of me having to (quickly) modify the function above, even if I have to specify how to deal with each property and value and how to combine each?
If it helps, the background of this is that I'm using a RestTemplate (Spring) to make a GET request to a different server, and I want to pass a specific object's properties/values in the URL. I understand I can use something like:
restTemplate.getForObject("URL?C1prop1={C1Prop1}&...", String.class, C1Object);
I believe the properties will be automatically mapped. But like I said, I don't want to have to make a different URL template and method for each object type. I'm hoping to have something like the following:
public String getRequest(String url, Object obj) {
String serializedUri = SERIALIZE_URI(obj);
String response = restTemplate.getForObject("URL?" + serializedUri, String.class);
return response;
}
where SERIALIZE_URI is where I'd handle it. And I could call it like getRequest("whatever", C1Object); and getRequest("whateverElse", C2Object);.
I think, solution number 4 is OK. It is simple to understand and clear.
I propose similar solution in which we can use #JsonAnySetter annotation. Please, see below example:
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.ObjectMapper;
public class JacksonProgram {
public static void main(String[] args) throws Exception {
C1 c1 = new C1();
c1.setProp1("a");
c1.setProp3("c");
User user = new User();
user.setName("Tom");
user.setSurname("Irg");
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.convertValue(c1, UriFormat.class));
System.out.println(mapper.convertValue(user, UriFormat.class));
}
}
class UriFormat {
private StringBuilder builder = new StringBuilder();
#JsonAnySetter
public void addToUri(String name, Object property) {
if (builder.length() > 0) {
builder.append("&");
}
builder.append(name).append("=").append(property);
}
#Override
public String toString() {
return builder.toString();
}
}
Above program prints:
prop1=a&prop2=null&prop3=c
name=Tom&surname=Irg
And your getRequest method could look like this:
public String getRequest(String url, Object obj) {
String serializedUri = mapper.convertValue(obj, UriFormat.class).toString();
String response = restTemplate.getForObject(url + "?" + serializedUri, String.class);
return response;
}
Lets we have c1.
c1.setC1prop1("C1prop1");
c1.setC1prop2("C1prop2");
c1.setC1prop3("C1prop3");
Converts c1 into URI
UriComponentsBuilder.fromHttpUrl("http://test.com")
.queryParams(new ObjectMapper().convertValue(c1, LinkedMultiValueMap.class))
.build()
.toUri());
After we will have
http://test.com?c1prop1=C1prop1&c1prop2=C1prop2&c1prop3=C1prop3
I use FlexJson for serialization, the only problem is that it generates the field names lower case while I need them to start with upper case:
class Person
{
String name;
public String getName() { return name;}
}
When serialized the field is serialized as name, while I need it to be Name.
How can I specify the output field name? Is there some attribute I can put to specify the required serialization name?
You can achieve this by using a Custom Transformer. As per Flexjson page transformer is:
Responsible for deciding how to translate the passed in object to
JSON, making the appropriate calls on the JSONContext object to output
the JSON, and/or passing the object along the transformation process.
Flexjson has provided an abstract class AbstractTransformer for this purpose; Extend and override transform(Object object) to handle the transformation by yourself.
Pasted below is the code of FieldNameTransformer which I wrote for specifying the field name s manually:
public class FieldNameTransformer extends AbstractTransformer {
private String transformedFieldName;
public FieldNameTransformer(String transformedFieldName) {
this.transformedFieldName = transformedFieldName;
}
public void transform(Object object) {
boolean setContext = false;
TypeContext typeContext = getContext().peekTypeContext();
//Write comma before starting to write field name if this
//isn't first property that is being transformed
if (!typeContext.isFirst())
getContext().writeComma();
typeContext.setFirst(false);
getContext().writeName(getTransformedFieldName());
getContext().writeQuoted(object.toString());
if (setContext) {
getContext().writeCloseObject();
}
}
/***
* TRUE tells the JSONContext that this class will be handling
* the writing of our property name by itself.
*/
#Override
public Boolean isInline() {
return Boolean.TRUE;
}
public String getTransformedFieldName() {
return this.transformedFieldName;
}
}
Following is how to use this custom transformer:
JSONSerializer serializer = new JSONSerializer().transform(new FieldNameTransformer("Name"), "name");
where original field's name is 'name' but in json ouput it will be replaced with Name.
Sample out:
{"Name":"Abdul Kareem"}