I want to take "ids" and assign it to an arraylist. config.json file is here:
{
"users":[
{"user id":1,"user name":"A","user type":"bot1", "ids": [1 ,2]},
{"user id":2,"user name":"B","user type":"bot2","ids": [1 ,2]},
{"user id":3,"user name":"C","user type":"bot3","ids": [2 ,3]}
]
}
To read this json file I have tried this:
JSONArray jsonArrayForUsers = (JSONArray) jsonObject.get("users");
for (int i=0; i<jsonArrayForUsers.size(); i++) {
JSONObject obj2 = (JSONObject) jsonArrayForUsers.get(i);
long userId = (long) obj2.get("user id");
String userName = (String) obj2.get("user name");
String userType = (String) obj2.get("user type");
JSONArray jsonDatasetIds = (JSONArray) jsonObject.get("ids");
List <Integer> list = Arrays.asList(jsonDatasetIds);// Trying to covert JSONArray into an array but error occurs
//Type mismatch: cannot convert from List<JSONArray> to List<Integer>
users.add(new User((int)userId, userName, userType,list));
}
I could read "user id", "user name" , "user type" correctly. But I don't know how to read -"ids": [1 ,2]- part and create an arraylist from it.
Edit:
Problem solved after I've changed
//It should've been 'obj2.get()'
JSONArray jsonDatasetIds = (JSONArray) obj2.get("ids");
for(int a = 0; i<jsonDatasetIds.size();i++){
list.add((int)jsonDatasetIds.get(a));
}
users.add(new User((int)userId, userName, userType,list));
But now I can not add values from 'jsonDatasetIds' to 'list'.
In other words I can not take values from JSONArray.
There are many ways to improve the code, let's start by reformulating the problem: You need to go from a JSON string to a model object with all the attributes mapped.
There are good libraries for doing just this, like Jackson and Gson, but it can also be done with json-simple 1.1.1 as you are doing.
Assuming your model object looks like this:
public class User {
private int id;
private String name;
private String type;
private List<Integer> ids;
// and constructor + getters + setters
}
And starting from the JSON you provided:
{
"users":[
{"user id":1, "user name":"A", "user type":"bot1", "ids":[1, 2]},
{"user id":2, "user name":"B", "user type":"bot2", "ids":[1, 2]},
{"user id":3, "user name":"C", "user type":"bot3", "ids":[2, 3]}
]
}
We can make a first attempt that looks like this:
public static void main(String[] args) throws ParseException {
String json =
"{ \"users\":[" +
" {\"user id\":1,\"user name\":\"A\",\"user type\":\"bot1\", \"ids\": [1 ,2]}," +
" {\"user id\":2,\"user name\":\"B\",\"user type\":\"bot2\",\"ids\": [1 ,2]}," +
" {\"user id\":3,\"user name\":\"C\",\"user type\":\"bot3\",\"ids\": [2 ,3]}" +
" ]" +
"}";
List<User> result = new ArrayList<>();
JSONParser parser = new JSONParser();
JSONObject root = (JSONObject) parser.parse(json);
List<JSONObject> users = (List<JSONObject>) root.get("users");
for (JSONObject user: users) {
List<Integer> userIds = new ArrayList<>();
for (Long id : (List<Long>) user.get("ids")) {
userIds.add(id.intValue());
}
result.add(new User(((Long)user.get("user id")).intValue(), (String) user.get("user name"), (String) user.get("user type"), userIds));
}
System.out.println(result);
}
As you can see a JSONArray can be directly casted to a List, and if we look at the signature of JSONArray class we can understand why:
public class JSONArray extends ArrayList implements List, JSONAware, JSONStreamAware
JSONArray is actually extending ArrayList so you do not need to create a new one and that is why the line List<JSONObject> users = (List<JSONObject>) root.get("users"); works.
Now that you have a list its possible to iterate over the elements with the usual foreach loop for (JSONObject user: users) {...} and process each element.
For the internal "ids" we could do the same thing but from your code it seems the ids must be integers and json-simple returns Long objects, so we need to convert them and that is why the second loop is there (if the model object accepted a List<Long> it would not be needed).
A different way for doing the same thing is with java 8 streams, specifying the different steps you need to convert the source object into the destination one:
public static void main(String[] args) throws ParseException {
String json =
"{ \"users\":[" +
" {\"user id\":1,\"user name\":\"A\",\"user type\":\"bot1\", \"ids\": [1 ,2]}," +
" {\"user id\":2,\"user name\":\"B\",\"user type\":\"bot2\",\"ids\": [1 ,2]}," +
" {\"user id\":3,\"user name\":\"C\",\"user type\":\"bot3\",\"ids\": [2 ,3]}" +
" ]" +
"}";
JSONParser parser = new JSONParser();
JSONObject root = (JSONObject) parser.parse(json);
List<User> result = ((List<JSONObject>)root.get("users"))
.stream()
.map(user -> new User(
((Long)user.get("user id")).intValue(),
(String) user.get("user name"),
(String) user.get("user type"),
((List<Long>) user.get("ids"))
.stream()
.map(Long::intValue)
.collect(Collectors.toList())))
.collect(Collectors.toList());
System.out.println(result);
}
In my opinion the stream api is more clear in situations when you need to go step by step transforming a list of objects from one type to another, in this example it does not makes much of a difference but in more complex situations with many intermediate steps it can be a really useful tool.
Related
I have a CSV file that I'd like to store as a Java object. I would like the name of the columns to be the first dimension of the array, and key pair values the second dimension of the array. I've tried different solutions (mostly LinkedHashMaps) but none seem to work properly.
The CSV looks like this:
TimeStamp;Column 1;Column 2;Column3
1385733406;Value1;Value12;Value13
1385733409;Value21;Value22;Value23
1385733411;Value31;Value32;Value33
I would like the array to look something like this:
["Column 1"]
["1385733406","Value1"]
["1385733409","Value21"]
["1385733411","Value31"]
["Column 2"]
["1385733406","Value2"]
["1385733409","Value22"]
["1385733411","Value32"]
["Column 3"]
["1385733406","Value2"]
["1385733409","Value22"]
["1385733411","Value33"]
This way, I would be able to query the object and retrieve all the key pair values from a given column, for instance, all the data from Column 1. Using HashMaps doesn't seem to work because they require two arguments, and doing this doesn't seem to be the proper way. This is the code I could come up with so far, which I don't think is the right track but it's all I could come up with. I'm using OpenJDK 1.7
public class CsvCollection {
public Map<String,Map<String,Integer>> Results = new LinkedHashMap<String, Map<String,Integer>>();
public CsvCollection(){
}
public void parseCsvResultFile(File csvFile){
CSVReader reader = null;
List myEntries = null;
try {
reader = new CSVReader(new FileReader(csvFile.getAbsolutePath()), ';');
} catch (FileNotFoundException e) {
System.out.println("Error opening [], aborting parsing");
}
try {
myEntries = reader.readAll();
} catch (IOException e) {
System.out.println("Error reading content of CSV file (but file was opened)");
}
for(String header: (String[]) myEntries.get(0)){
Results.put(header, null);
// What now?
}
}
}
You can make 2 change as follows to implements the function you needed.
1) Change the following code
public Map<String,Map<String,Integer>> Results = new LinkedHashMap<String, Map<String,Integer>>();
to
public Map<String, List<String[]>> Results = new LinkedHashMap<String, List<String[]>>();
This change is made because for a specify column, like Column 1, it has 3 rows with Timestamp and corresponding Column value. You need to use a List to store them.
2) Change the following for-loop
for(String header: (String[]) myEntries.get(0)){
Results.put(header, null);
// What now?
}
to
String[] headerColumns = (String[]) myEntries.get(0);
// First column is TimeStamp, skip it
for (int i = 1; i < headerColumns.length; i++) {
List<String[]> list = new ArrayList<String[]>();
for (int rowIndex = 1; rowIndex < myEntries.size(); rowIndex++) {
String[] row = (String[]) myEntries.get(rowIndex);
list.add(new String[] { row[0], row[i] });
}
Results.put(headerColumns[i], list);
}
With the above 2 changes, if you print the Results (type of Map< String, List< String[] > >) in console using the following code,
for(Map.Entry<String, List<String[]>> entry : Results.entrySet())
{
System.out.printf("[%s]\n",entry.getKey());
for(String[] array : entry.getValue())
{
System.out.println(Arrays.toString(array));
}
}
you will get the result you need:
[Column 1]
[1385733406, Value1]
[1385733409, Value21]
[1385733411, Value31]
[Column 2]
[1385733406, Value12]
[1385733409, Value22]
[1385733411, Value32]
[Column3]
[1385733406, Value13]
[1385733409, Value23]
[1385733411, Value33]
Note: the above example is executed using the content from a CSV file below:
TimeStamp;Column 1;Column 2;Column3
1385733406;Value1;Value12;Value13
1385733409;Value21;Value22;Value23
1385733411;Value31;Value32;Value33
Please help!!
What is the correct way to send List of String as a parameter to webservice ?
List < SObject > ObjectContents; // {get; set;} contains records of selected object
List str3 = new List ();
String FormattedValue;
for (SObject a : for (SObject a : ObjectContents)) // for (SObject a : ObjectContents)
{
for(String field:fieldApis){ // fieldApis contains list of fieldnames
FormattedValue = '\'' + a.get(field) + '\'' ; //fetches value of each field
}
str3.add(FormattedValue );
}
//sending data to webservice
sqlArray19.ArrayOfstring a= new sqlArray19.ArrayOfstring();
SQLServerConnector9.BasicHttpBinding_IService1 stub = new SQLServerConnector9.BasicHttpBinding_IService1();
//sqlArray19 and SQLServerConnector9 classes were formed while importing wsdl into Salesforce
List<String> insertMsg = stub.InsertQuery(str3); // getting error in this line
"Compile Error: Method does not exist or incorrect signature: [SQLServerConnector9.BasicHttpBinding_IService1].InsertQuery(LIST<String>)"
.net webservice which will fetch values from Salesforce and return those values
public List<String> InsertQuery(List<String> Values)
{
return Values ;
}
Collections can be troublesome data types when working across platforms with web services. Try converting your List into a string[] (and changing your method, of course).
I have a class with multiple Lists. Is the class design correct for gson to work?
My class:
Class Data
{
List<String> actor;
List<Integer> text_relevance;
List<String> title;
}
The json string is as follows ...
Is the class design for this json correct?
{
"data":
{
"actor":["Abercrombie, Ian","Baker, Dee Bradley","Burton, Corey",
"Eckstein, Ashley","Futterman, Nika","Kane, Tom",
"Lanter, Matt","Taber, Catherine","Taylor, James Arnold",
"Wood, Matthew"],
"text_relevance":["308"],
"title":["Star Wars: The Clone Wars"]
}
}
Yes, your code is correct. I deserialized it with this code:
Gson gson = new Gson();
Type type = new TypeToken<Map<String, Data>>() {}.getType();
Map<String, Data> map = gson.fromJson(json, type);
Data data = map.get("data");
Note that Gson will convert strings like "308" to the corresponding integer. This is generally used to permit very large values from losing precision. But it works out just fine for your case as well.
I'm using a CellTable to display entities' information stored in the Datastore. Data type of the parameters are String and int.
I decided to use SelectionCell to show the value of every parameter. This works perfectly when it comes to String data type, but it fails with int data type.
For instance, I have a parameter called:
String name;
Possible values for this parameter are: "Name1", "Name2" or "Name3". I have these values in the SelectionCell, so if an entity has a parameter name = "Name2", SelectionCell displays "Name2"
List<String> names= new ArrayList<String>();
names.add("Name1");
names.add("Name2");
names.add("Name3");
SelectionCell nameCell = new SelectionCell(names);
Column<Entity, String> nameColumn = new Column<Entity, String>(nameCell){
#Override
public String getValue(Entity object){
return object.getName();
}
};
cellTable.addColumn(nameColumn, "Name");
Now, I have a parameter called:
int age;
Possible values for this parameter are: 18, 19, 20,... ,65. I have these values in the SelectionCell, but if an entity has a parameter age = 25, SelectionCell doesn't display that value, it displays 18.
List<String> ages= new ArrayList<String>();
for(int i = 18; i <= 65; i++){
ages.add("" + i);
}
SelectionCell ageCell = new SelectionCell(ages);
Column<Entity, String> ageColumn = new Column<Entity, String>(ageCell){
#Override
public String getValue(Entity object){
return "" + object.getAge();
}
};
cellTable.addColumn(ageColumn, "Age");
How can I solve that?
Cheers.
Try Creating your List of Ages before creating the dataGrid.
I'm using Spring JdbcTemplate, and I'm stuck at the point where I have a query that updates a column that is actually an array of int. The database is postgres 8.3.7.
This is the code I'm using :
public int setUsersArray(int idUser, int idDevice, Collection<Integer> ids) {
int update = -666;
int[] tipi = new int[3];
tipi[0] = java.sql.Types.INTEGER;
tipi[1] = java.sql.Types.INTEGER;
tipi[2] = java.sql.Types.ARRAY;
try {
update = this.jdbcTemplate.update(setUsersArrayQuery, new Object[] {
ids, idUser, idDevice }, tipi);
} catch (Exception e) {
e.printStackTrace();
}
return update;
}
The query is "update table_name set array_column = ? where id_user = ? and id_device = ?".
I get this exception :
org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; SQL [update acotel_msp.users_mau set denied_sub_client = ? where id_users = ? and id_mau = ?]; The column index is out of range: 4, number of columns: 3.; nested exception is org.postgresql.util.PSQLException: The column index is out of range: 4, number of columns: 3.
Caused by: org.postgresql.util.PSQLException: The column index is out of range: 4, number of columns: 3.
I've looked into spring jdbc template docs but I can't find any help, I'll keep looking, anyway could someone point me to the right direction? Thanks!
EDIT :
Obviously the order was wrong, my fault...
I tried both your solutions, in the first case I had this :
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [update users set denied_sub_client = ? where id_users = ? and id_device = ?]; nested exception is org.postgresql.util.PSQLException: Cannot cast an instance of java.util.ArrayList to type Types.ARRAY
Trying the second solution I had this :
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [update users set denied_sub_client = ? where id_users = ? and id_device = ?]; nested exception is org.postgresql.util.PSQLException: Cannot cast an instance of [Ljava.lang.Object; to type Types.ARRAY
I suppose i need an instance of java.sql.Array, but how can I create it using JdbcTemplate?
After struggling with many attempts, we settled to use a little helper ArraySqlValue to create Spring SqlValue objects for Java Array Types.
usage is like this
jdbcTemplate.update(
"UPDATE sometable SET arraycolumn = ?",
ArraySqlValue.create(arrayValue))
The ArraySqlValue can also be used in MapSqlParameterSource for use with NamedParameterJdbcTemplate.
import static com.google.common.base.Preconditions.checkNotNull;
import java.sql.Array;
import java.sql.JDBCType;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Locale;
import org.springframework.jdbc.core.StatementCreatorUtils;
import org.springframework.jdbc.support.SqlValue;
public class ArraySqlValue implements SqlValue {
private final Object[] arr;
private final String dbTypeName;
public static ArraySqlValue create(final Object[] arr) {
return new ArraySqlValue(arr, determineDbTypeName(arr));
}
public static ArraySqlValue create(final Object[] arr, final String dbTypeName) {
return new ArraySqlValue(arr, dbTypeName);
}
private ArraySqlValue(final Object[] arr, final String dbTypeName) {
this.arr = checkNotNull(arr);
this.dbTypeName = checkNotNull(dbTypeName);
}
#Override
public void setValue(final PreparedStatement ps, final int paramIndex) throws SQLException {
final Array arrayValue = ps.getConnection().createArrayOf(dbTypeName, arr);
ps.setArray(paramIndex, arrayValue);
}
#Override
public void cleanup() {}
private static String determineDbTypeName(final Object[] arr) {
// use Spring Utils similar to normal JdbcTemplate inner workings
final int sqlParameterType =
StatementCreatorUtils.javaTypeToSqlParameterType(arr.getClass().getComponentType());
final JDBCType jdbcTypeToUse = JDBCType.valueOf(sqlParameterType);
// lowercasing typename for Postgres
final String typeNameToUse = jdbcTypeToUse.getName().toLowerCase(Locale.US);
return typeNameToUse;
}
}
this code is provided in the Public Domain
private static final String ARRAY_DATATYPE = "int4";
private static final String SQL_UPDATE = "UPDATE foo SET arr = ? WHERE d = ?";
final Integer[] existing = ...;
final DateTime dt = ...;
getJdbcTemplate().update(new PreparedStatementCreator() {
#Override
public PreparedStatement createPreparedStatement(final Connection con) throws SQLException {
final PreparedStatement ret = con.prepareStatement(SQL_UPDATE);
ret.setArray(1, con.createArrayOf(ARRAY_DATATYPE, existing));
ret.setDate(2, new java.sql.Date(dt.getMillis()));
return ret;
}
});
This solution is kind of workaround using postgreSQL built-in function, which definitely worked for me.
reference blog
1) Convert String Array to Comma Separated String
If you are using Java8, it's pretty easy. other options are here
String commaSeparatedString = String.join(",",stringArray); // Java8 feature
2) PostgreSQL built-in function string_to_array()
you can find other postgreSQL array functions here
// tableName ( name text, string_array_column_name text[] )
String query = "insert into tableName(name,string_array_column_name ) values(?, string_to_array(?,',') )";
int[] types = new int[] { Types.VARCHAR, Types.VARCHAR};
Object[] psParams = new Object[] {"Dhruvil Thaker",commaSeparatedString };
jdbcTemplate.batchUpdate(query, psParams ,types); // assuming you have jdbctemplate instance
The cleanest way I found so far is to first convert the Collection into an Integer[] and then use the Connection to convert that into an Array.
Integer[] idArray = ids.toArray(new Integer[0]);
Array idSqlArray = jdbcTemplate.execute(
(Connection c) -> c.createArrayOf(JDBCType.INTEGER.getName(), idArray)
);
update = this.jdbcTemplate.update(setUsersArrayQuery, new Object[] {
idSqlArray, idUser, idDevice })
This is based on information in the documentation: https://jdbc.postgresql.org/documentation/head/arrays.html
The argument type and argument is not matching.
Try changing the argument type order
int[] tipi = new int[3];
tipi[0] = java.sql.Types.ARRAY;
tipi[1] = java.sql.Types.INTEGER;
tipi[2] = java.sql.Types.INTEGER;
or use
update = this.jdbcTemplate.update(setUsersArrayQuery, new Object[] {
ids.toArray(), idUser, idDevice })
and see if it works
http://valgogtech.blogspot.com/2009/02/passing-arrays-to-postgresql-database.html explains how to create java.sql.Array postgresql
basically Array.getBaseTypeName should return int and Array.toString should return the array content in "{1,2,3}" format
after you create the array you can set it using preparedstatement.setArray(...)
from PreparedStatementCreator e.g.
jdbcTemplate.update(
new PreparedStatementCreator() {
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
Good Luck ..
java.sql.Array intArray = connection.createArrayOf("int", existing);
List<Object> values= new ArrayList<Object>();
values.add(intArray);
values.add(dt);
getJdbcTemplate().update(SQL_UPDATE,values);