I have a JSON array like this :
[
{"_id": {"$oid":"57e9e4b1f36d281c4b330509"}, "user": "edmtdev" },
{"_id": {"$oid":"57e9e4cec2ef164375c4c292"}, "user": "admin1234" },
{"_id": {"$oid":"57ea1b0ac2ef164375c5ff1e"}, "username": "admin34" }
]
This is my User.class, used to store all data:
public class User{
private Id id;
private String user;
public Id getId() {
return id;
}
public void setId(Id id) {
this.id = id;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
}
And my Id.class, used to store the ID:
public class Id {
private String $oid;
public String get$oid() {
return $oid;
}
public void set$oid(String $oid) {
this.$oid = $oid;
}
}
I am using GSON in Java to get my users as a List<User>:
List<User> users = new ArrayList<User>();
Gson gson = new Gson();
Type listType = new TypeToken<List<User>>(){}.getType();
users = gson.fromJson(s,listType);
The problem is, I get users with username but no ID, $oid is not registered. Can someone help me understanding what does not work in this piece of code ?
You must replace id in User class by:
private Id _id;
because your json is _id, not id. And your json string at the end is wrong, is user, not username
#SerializedName("_id")
private Id id;
This is another approach.You can use this above annotation also.
Related
I have a Java Class named User with
#Column(name = "id")
private Long id;
#NotNull
#Column(name = "NAME")
private String name;
I am trying to get some details in a list and convert it into JSOn like so:
Session session = this.sessionFactory.getCurrentSession();
String queryString="select id,name from User where unit=:name";
Query query= sessionFactory.getCurrentSession().createQuery(queryString);
query.setParameter("name", name);
List<User> users= (List<User>) query.list();
Gson gson = new GsonBuilder().setPrettyPrinting().create();
Map<String, List<User>> wrap = new HashMap<>();
wrap.put("users", users); // wrap user list in a map
String json = gson.toJson(wrap);
This produces a JSON
{
"users": [
[
1,
"Room"
],
[
2,
"Regi"
],
]
}
How do I change it so that I get a JSON like
{
"users": [
[
"id":1,
"name":"Rovom"
],
[
"id":2,
"name":"Regi"
],
]
}
Edit
I realized it is the query that is causing the issue. If i use
String queryString="from User where unit=:name";
It gives the correct format. How do I fix this?
Whith jackson, it'll look like this:
String json = new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueToString(wrap);
You'd want jackson-core and jackson-databind for this at least.
Full example using Jackson:
public static class User {
private Long id;
private String name;
public User(long i, String n) {
id = i;
name = n;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static void main(String... args) {
try {
Map<String,Object> map = new HashMap<>();
map.put("users", Arrays.asList(new User(1, "Stack"), new User(2, "Overflow")));
System.out.println(new ObjectMapper().writerWithDefaultPrettyPrinter()
.writeValueAsString(map));
} catch (Exception e) {
e.printStackTrace();
}
}
produced this output:
{
"users" : [ {
"id" : 1,
"name" : "Stack"
}, {
"id" : 2,
"name" : "Overflow"
} ]
}
Hm, looks like type erasure at runtime.
Your List<User> is with the first query actually a List<Object[]> as which it got serialized. Would you try to access an User-object out of the list, you'd get a runtime error, I suppose.
See hibernate documentation:
Return the query results as a List. If the query contains multiple
results pre row, the results are returned in an instance of Object[].
EDIT
to get a list of Users with only the two fields filled, create the apropriate constructur and use a query like
select new package.path.to.class.User(id,name) from User where unit=:name"
As mentioned by user #Turo this is because of type erasure at runtime.
To fix this, the query has to be changed to
String queryString="select id,name from User where unit=:name";
Query query= sessionFactory.getCurrentSession().createSQLQuery(queryString).addScalar("name", new StringType()).addScalar("id", new IntType()).setResultTransformer(Transformers.aliasToBean(User.class));
query.setParameter("name", name);
the addScalar() will map the values to the User objects and this gives the required result.
I am trying to create a springboot application using MongoDB and a Rest controller and connect objects together using DBRef instead of classic Jpa annotations like OneToMany etc. The purpose is to print all the bookmarks for a specific account. The list of bookmarks is found by the username but it seems that it doesn't work.
These are my classes:
#Document
public class Account {
#DBRef
private Set<Bookmark> bookmarkSet = new HashSet<>();
#Id
private String id;
#JsonIgnore
private String username;
private String password;
public Account(String username, String password) {
this.username = username;
this.password = password;
}
public void setBookmarkSet(Set<Bookmark> bookmarkSet) {
this.bookmarkSet = bookmarkSet;
}
public String getId() {
return id;
}
}
#Document
public class Bookmark {
#DBRef
#JsonIgnore
private Account account;
#Id
private String id;
private String uri;
private String description;
public Bookmark(Account account, String uri, String description) {
this.account = account;
this.uri = uri;
this.description = description;
}
public Account getAccount() {
return account;
}
public String getId() {
return id;
}
public String getUri() {
return uri;
}
public String getDescription() {
return description;
}
}
repositories:
public interface AccountRepository extends MongoRepository<Account, Long> {
Optional<Account> findOneByUsername(String username);
}
public interface BookmarkRepository extends MongoRepository<Bookmark, Long> {
Collection<Bookmark> findByAccountUsername(String username);
}
And RestController:
#RestController
#RequestMapping("/{userId}/bookmarks")
public class BookmarkRestController {
private final AccountRepository accountRepository;
private final BookmarkRepository bookmarkRepository;
#Autowired
public BookmarkRestController(AccountRepository accountRepository, BookmarkRepository bookmarkRepository) {
this.accountRepository = accountRepository;
this.bookmarkRepository = bookmarkRepository;
}
#RequestMapping(value = "/{bookmarkId}", method = RequestMethod.GET)
Bookmark readBookmark(#PathVariable String userId, #PathVariable Long bookmarkId) {
this.validateUser(userId);
return bookmarkRepository.findOne(bookmarkId);
}
#RequestMapping(method = RequestMethod.GET)
Collection<Bookmark> readBookmarks(#PathVariable String userId) {
this.validateUser(userId);
return this.bookmarkRepository.findByAccountUsername(userId);
}
private void validateUser(String userId) {
this.accountRepository.findOneByUsername(userId).orElseThrow(() -> new UserNotFoundException(userId));
}
}
After I run the application I get this error:
Invalid path reference account.username! Associations can only be pointed to directly or via their id property!
I'm not sure you have the right schema design. I assume you've modeled you objects based on a relational database type model, where the data is normalised and data is split across multiple tables, with relationships captured using Ids. With MongoDB you can structure and store your data with the heirarchy simply contained in within the one document.
So in your example the Bookmark would not be a Document itself, but would be a sub document of the Account. Remove the #Document annotation from the Bookmark object, and the #DBRef annotations, and simply store the Bookmarks within the Account document.
This would give you a schema more like this:
{
"_id": 1,
"bookmarkSet": [
{
"uri": "http://www.foo.com",
"description": "foo"
},
{
"uri": "http://www.bar.com",
"description": "bar"
}
],
"username": "John",
"password": "password"
}
*Note: if you make the bookmarks sub documents you can remove the _id member from the Bookmark object
The best design will depend on how many bookmarks you expect each account to have. If its only a few bookmarks then what I suggested would work well. If you have thousands then you might want to structure it differently. There are lots of articles about schema design in NoSQL database. This one covers the options for embedding subdocuments quite well:
http://blog.mongodb.org/post/87200945828/6-rules-of-thumb-for-mongodb-schema-design-part-1
I have the following json from the Server. It is a json array with different objects. I want to identify the user objects based on the key "type" and add them to a user hashmap and fetch user to show information in my view containing the "payments" object. I am using gson and retrofit. TIA
"included":[
{
"id":"1",
"type":"payments",
"attributes":{
"amount_cents":100,
"amount_currency":"INR",
"description":"Test description!!",
"created_at":"2016-03-01T11:30:53Z",
"status":"paid",
"paid_at":null,
"charged_at":null,
"formatted_amount":"Rs1.00"
},
"relationships":{
"sender":{
"data":{
"id":"2",
"type":"users"
}
},
"receiver":{
"data":{
"id":"1",
"type":"users"
}
}
}
},
{
"id":"2",
"type":"users",
"attributes":{
"first_name":"Rob",
"last_name":"Thomas"
}
},
{
"id":"1",
"type":"users",
"attributes":{
"first_name":"Matt",
"last_name":"Thomas"
}
}]
My classes are
public class ActivityFeedItem implements IFeedItem {
#SerializedName("id")
String id;
#SerializedName("type")
String type;
#SerializedName("attributes")
Attributes attributes;
protected class Attributes {
double amount_cents;
String amount_currency;
String description;
String created_at;
String status;
String paid_at;
String charged_at;
String formatted_amount;
Relationships relationships;
public double getAmount_cents() {
return amount_cents;
}
public String getAmount_currency() {
return amount_currency;
}
public String getDescription() {
return description;
}
public String getCreated_at() {
return created_at;
}
public String getStatus() {
return status;
}
public String getPaid_at() {
return paid_at;
}
public String getCharged_at() {
return charged_at;
}
public String getFormatted_amount() {
return formatted_amount;
}
public Relationships getRelationships() {
return relationships;
}
}
}
and
public class UserFeedItem implements IFeedItem {
#SerializedName("id")
String id;
#SerializedName("type")
String type;
#SerializedName("attributes")
Attributes attributes;
public class Attributes {
#SerializedName("first_name")
String first_name;
#SerializedName("last_name")
String last_name;
}
}
This is pretty easy if you just put your JSON response String into a JSONArray. Then you can just access the type field and test if it's users. Like this:
JSONArray jsonArray = new JSONArray(yourServerResponseString);
for(int i=0; i<jsonArray.length(); i++) {
JSONObject object = (JSONObject) jsonArray.get(i);
String type = object.getString("type");
if(type.equals("users")) {
//add to your users HashMap
}
}
First of all create an array of objects from you JSON using GSON as below
Gson gson= new Gson();
String jsonString= yourJsonObject.getString("included");
ActivityFeedItem[] activityFeedArray=gson.fromJson(jsonString,ActivityFeedItem[].class);
Now your activityFeedArray contains all the feedItems you get in JSON. Then you can iterate through it as you would in any array and add to hashmap when type is user as below-
for(ActivityFeedItem item:activityFeedArray) {
if(item.type.equals("users")) {
//add to your users HashMap
}
}
I'm new to Java. I'm using Spring to consume a REST api that outputs JSON. With the tutorials on the Spring website I can easily have the JSON response converted to an object of my desired class. The problem is now that one of the keys in the JSON response is $id. I cannot make a variable with a dollar sign in it. I assume I should define some configuration somewhere that such a name would be converted into something acceptable. I don't know how.
My Rest request code:
protected LoginResult doInBackground(Void... params) {
try {
Log.i(TAG, "Making Login request");
//TODO: Make this a setting
final String url = "https://someurl.com/api/login";
LoginCredentials login = new LoginCredentials("foo#bar.com", "qwerty123");
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
LoginResult result = restTemplate.postForObject(url, login, LoginResult.class);
Log.d(TAG, "Got the LoginResult.");
return result;
} catch (Exception e) {
//TODO: Exception handling
Log.e(TAG, e.getMessage(), e);
}
return null;
}
The resulting JSON looks something like this:
{
"_id":{
"$id":"98765432"
},
"name":"Person Guy",
"email":"foo#bar.com",
"roles":[
"user"
],
"active":true,
"created":{
"sec":1439117849,
"usec":856000
},
"session":{
"token":"12345678",
"user_id":"98765432",
"created":{
"sec":1439134272,
"usec":0
},
"last_extended":{
"sec":1439134272,
"usec":0
},
"expires":{
"sec":1439998272,
"usec":0
}
}
}
The $id part is where things get difficult. The LoginResult class looks like this:
#JsonIgnoreProperties(ignoreUnknown = true)
public class LoginResult {
private String name;
private String email;
private MongoId _id;
/* Getters and setters */
}
The MongoId class looks like this (The JsonIgnoreProperties is now added to avoid exceptions):
#JsonIgnoreProperties(ignoreUnknown = true)
public class MongoId {
private String id; //This is $id in the JSON response.
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
Any help would be largely appreciated.
You can use the #JsonProperty("$id") annotation in MongoId to tell how the JSON is mapped to your Java object:
#JsonIgnoreProperties(ignoreUnknown = true)
public class MongoId {
#JsonProperty("$id")
private String id; //This is $id in the JSON response.
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
Here is a quick overview for reference.
I have the following JSON to represent the server response for a salt request:
{
"USER":
{
"E_MAIL":"email",
"SALT":"salt"
},
"CODE":"010"
}
And i tried to map it with the following POJO:
public class SaltPOJO {
private String code = null;
private User user = null;
#Override
public String toString() {
return this.user.toString();
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public class User {
private String e_mail = null;
private String salt = null;
#Override
public String toString() {
return this.e_mail + ": " + this.salt;
}
public String getE_mail() {
return e_mail;
}
public void setE_mail(String e_mail) {
this.e_mail = e_mail;
}
public String getSalt() {
return salt;
}
public void setSalt(String salt) {
this.salt = salt;
}
}
}
Now everytime i do this:
Gson gson = new Gson();
SaltPOJO saltPojo = gson.fromJson(json.toString(), SaltPOJO.class);
Log.v("Bla", saltPojo.toString());
The saltPojo.toString() is null. How can i map my JSON into POJO using Gson?
Is the order of my variables important for the Gson mapping?
Is the order of my variables important for the Gson mapping?
No, that's not the case.
How can i map my JSON into POJO using Gson?
It's Case Sensitive and the keys in JSON string should be same as variable names used in POJO class.
You can use #SerializedName annotation to use any variable name as your like.
Sample code:
class SaltPOJO {
#SerializedName("CODE")
private String code = null;
#SerializedName("USER")
private User user = null;
...
class User {
#SerializedName("E_MAIL")
private String e_mail = null;
#SerializedName("SALT")
private String salt = null;
You don't have proper mapping between your getter and setter. If you change your json to something like below, it would work:
{
"user":
{
"email":"email",
"salt":"salt"
},
"code":"010"
}
If you are getting json form third party then unfortunately, you would have to change your pojo or you could use adapter.