I have a RESTful application that connects to MySQL database (raw paste here: https://pastebin.com/raw/3fBp3j0B) and prints out table data in JSON format.
If I System.out.println() some data from ResultSet, everything shows up correctly, but with the JSON API only the last row in the table is printed out, twice.
import java.sql.*;
import javax.json.*;
public class Tietokanta {
protected Connection yhteys = null;
protected Statement kysely = null;
protected ResultSet tulosjoukko = null;
public boolean avaaYhteys() {
boolean ok = true;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
yhteys = DriverManager.getConnection("jdbc:mysql://localhost/savukelaskuri?serverTimezone=UTC", "root", "");
} catch (Exception e) {
e.printStackTrace();
ok = false;
}
return ok;
}
public boolean suljeYhteys() {
boolean ok = true;
try {
this.yhteys.close();
} catch (Exception e) {
ok = false;
}
return ok;
}
}
...
import java.math.BigDecimal;
import javax.json.Json;
import javax.json.JsonArray;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.Produces;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PUT;
import static javax.ws.rs.client.Entity.json;
import javax.ws.rs.core.MediaType;
import org.json.JSONArray;
import org.json.JSONObject;
#Path("savukkeet")
public class ApiResource extends Tietokanta {
JSONObject jsonolio = new JSONObject();
JSONArray jsontaulu = new JSONArray();
#Context
private UriInfo context;
public ApiResource() {
this.avaaYhteys();
}
#GET
#Produces(MediaType.APPLICATION_JSON)
public String getJson() {
try {
kysely = yhteys.createStatement();
String sql = "SELECT * FROM kulutus";
tulosjoukko = kysely.executeQuery(sql);
while (tulosjoukko.next()) {
System.out.println(tulosjoukko.getString("pvm"));
jsonolio.put("id", tulosjoukko.getInt("id"));
jsonolio.put("pvm", tulosjoukko.getString("pvm"));
jsonolio.put("kulutus", tulosjoukko.getInt("kulutus"));
jsontaulu.put(jsonolio);
}
} catch (Exception e) {
e.printStackTrace();
}
return jsontaulu.toString(4);
}
}
I expect the result to be
[
{
"kulutus": 9,
"pvm": "2019-01-14 16:46:00",
"id": 1
},
{
"kulutus": 8,
"pvm": "2019-01-15 21:18:00",
"id": 2
}
]
but instead I get this
[
{
"kulutus": 8,
"pvm": "2019-01-15 21:18:00",
"id": 2
},
{
"kulutus": 8,
"pvm": "2019-01-15 21:18:00",
"id": 2
}
]
It should work if you create a new JSONObject for each iteration in the while loop:
while (tulosjoukko.next()) {
System.out.println(tulosjoukko.getString("pvm"));
jsonolio = new JSONObject();
jsonolio.put("id", tulosjoukko.getInt("id"));
jsonolio.put("pvm", tulosjoukko.getString("pvm"));
jsonolio.put("kulutus", tulosjoukko.getInt("kulutus"));
jsontaulu.put(jsonolio);
}
Java is pass-by-reference, so when you put a property to jsonolio it overrides the previous value even inside the JSONArray because it is still the same object
putting an object in another container does not make a copy for you. you have 1 json Object and you fill it twice. and you put 2 copies of it in the list. at the end the 1 object just has the second set of values in it. so that is what gets output.
put this line JSONObject jsonolio = new JSONObject(); just after while (tulosjoukko.next()) {
Related
I have a problem in my web service. It is because, on my first url path, it will check the plate number. Now, I want to get the input of the user from the first url path and use it on the second path. Is it possible? Here's the first url where I will scan the input of the user:
package com.taxisafe.server;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import com.taxisafe.connection.DatabaseConnection;
import com.taxisafe.json.JsonConstruction;
//PATH FOR CHECKING PLATE NUMBER
#Path("platecheck") //for the url
public class PlateNumberCheck {
#GET
//To get the full url : http://Ipaddress:portnumber/#path/#getPath
#Path("/check")
#Produces(MediaType.APPLICATION_JSON)
//Produces is for the response of JSON.
public String check(#QueryParam("platenumber") String platenumber){
String sagot = "";
if(checkInput(platenumber)){
sagot = JsonConstruction.JSONResponse("checked", true);
} else{
sagot = JsonConstruction.JSONResponse("checked", false, "Not in the database");
}
return sagot;
}
private boolean checkInput (String platenumber){
System.out.println("Check Input");
boolean output = false;
if(JsonConstruction.isNotNull(platenumber)){
try{
output = DatabaseConnection.checkPlate(platenumber);
} catch (Exception e){
output = false;
}
} else{
output = false;
}
return output;
}
}
Here is where I want to access the platenumber without using another String like taxi_plate_no
package com.taxisafe.server;
import java.util.ArrayList;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import com.google.gson.Gson;
import com.taxisafe.array.ArrayConnection;
import com.taxisafe.connection.DatabaseConnection;
import com.taxisafe.json.JsonConstruction;
import com.taxisafe.objects.Objects;
#Path("/displays")
public class DisplayTaxiDetails {
#GET
#Path("taxidetails")
#Produces(MediaType.APPLICATION_JSON)
public String taxidetails(#QueryParam("taxi_plate_no") String taxi_plate_no{
String sagot = "";
String taxidetails = null;
if(checkInput(taxi_plate_no)){
sagot = JsonConstruction.JSONResponse("checked", true);
ArrayList<Objects> taxiDetailsList = new ArrayList<Objects>();
try{
taxiDetailsList = new ArrayConnection().getTaxiDetails(taxi_plate_no);
Gson gson = new Gson();
taxidetails = gson.toJson(taxiDetailsList);
} catch (Exception e){
e.printStackTrace();
}
return taxidetails;
} else{
sagot = JsonConstruction.JSONResponse("checked", false, "Not in the database");
}
return sagot;
}
private boolean checkInput (String taxi_plate_no){
System.out.println("Check Input");
boolean output = false;
if(JsonConstruction.isNotNull(taxi_plate_no)){
try{
output = DatabaseConnection.checkPlate(taxi_plate_no);
} catch (Exception e){
output = false;
}
} else{
output = false;
}
return output;
}
}
I've recently starting working on a java webapp (JSP / Servlet) that was developed by the internal developer of a company.
This app randomly doesn't return data, and inspecting the log I found some NullPointerExceptions related to the classes' member variable which holds the database connection. Following the stack trace it seems that a second thread closes the connection after it ended its task leaving the first thread without a connection.
By the needs of the company the app uses different databases, one which rules appdata, and others which contain data the app has to retrieve. So every class attached to the main servlet may connect to one or more databases depending on the task it has to accomplish.
I'm not familiar with JavaEE but giving a look at the database connection class, I see nothing which protect threads from conflicting each other.
Which is the correct way to handle such connections?
This is the code of the Database handler:
package it.metmi.mmasgis.utils;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class DBManager
{
private String szDatabase;
private String szUsername;
private String szPassword;
private String szError;
private Connection db;
private boolean bConnected;
private Logger logger;
public DBManager(String szDBName)
{
this(szDBName, "", "");
}
public DBManager(String szDBName, String szName, String szPass)
{
szDatabase = szDBName;
szUsername = szName;
szPassword = szPass;
bConnected = false;
szError = "";
logger = LogManager.getFormatterLogger(DBManager.class.getName());
}
public boolean connect()
{
logger.entry();
try {
Class.forName("com.mysql.jdbc.Driver");
if(!szDatabase.isEmpty())
{
String szCon = "jdbc:mysql://localhost/" + szDatabase;
if(!szUsername.isEmpty())
{
szCon += "?user=" + szUsername;
if(!szPassword.isEmpty())
szCon += "&password=" + szPassword;
}
db = DriverManager.getConnection(szCon);
bConnected = true;
} else {
logger.error("No database name!!");
System.exit(0);
}
} catch(SQLException | ClassNotFoundException e) {
szError = e.getMessage();
e.printStackTrace();
logger.error("Can't connect: %s", e);
}
return logger.exit(bConnected);
}
public void disconnect()
{
logger.entry();
try {
db.close();
bConnected = false;
} catch(SQLException e) {
e.printStackTrace();
logger.error("Can't disconnect: %s", e);
}
logger.exit();
}
public boolean isConnected()
{
return bConnected;
}
public String getError()
{
return szError;
}
public ArrayList<HashMap<String,String>> query(String szQuery)
{
logger.entry(szQuery);
ArrayList<HashMap<String,String>> aResults = new ArrayList<HashMap<String,String>>();
int iCols = 0;
try {
Statement stmt = db.createStatement();
logger.info("Query: %s", szQuery);
ResultSet rs = stmt.executeQuery(szQuery);
ResultSetMetaData rsmd = rs.getMetaData();
iCols = rsmd.getColumnCount();
while(rs.next())
{
HashMap<String,String> pv = new HashMap<String,String>();
for(int i = 0; i < iCols; i++)
{
String szCol = rsmd.getColumnLabel(i + 1);
String szVal = rs.getString(i + 1);
pv.put(szCol, szVal);
}
aResults.add(pv);
}
rs.close();
stmt.close();
} catch(SQLException e) {
e.printStackTrace();
szError = e.getMessage();
logger.error("Error executing query: %s", e);
}
return logger.exit(aResults);
}
public boolean update(String szQuery)
{
logger.entry(szQuery);
boolean bResult = false;
try {
Statement stmt = db.createStatement();
logger.info("Query: %s", szQuery);
stmt.executeUpdate(szQuery);
bResult = true;
stmt.close();
} catch(SQLException e) {
e.printStackTrace();
szError = e.getMessage();
bResult = false;
logger.error("Error executing query: %s", e);
}
return logger.exit(bResult);
}
}
The class Task which all the servlet classes are based on, is a simple abstract class:
package it.metmi.mmasgis.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public abstract class Task
{
public abstract void doTask(HttpServletRequest request, HttpServletResponse response);
}
The class which throws NullPointerExceptions it this one, during the invocation of db.disconnect(). This class is called rapidly via AJAX 4 or 5 times from the interface written in JS.
package it.metmi.mmasgis.servlet.params;
import it.metmi.mmasgis.servlet.Task;
import it.metmi.mmasgis.utils.Const;
import it.metmi.mmasgis.utils.DBManager;
import it.metmi.mmasgis.utils.Query;
import it.metmi.mmasgis.utils.Utility;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class ClassType extends Task
{
private DBManager db = null;
private Logger logger = LogManager.getFormatterLogger(ClassType.class.getName());
#Override
public void doTask(HttpServletRequest request, HttpServletResponse response)
{
logger.entry(request, response);
String szCensimento = Utility.getParameter(request, "censimento");
String szCategoria = Utility.getParameter(request, "category");
ArrayList<HashMap<String,String>> aClasses = new ArrayList<HashMap<String,String>>();
PrintWriter out = null;
logger.debug("Census: %s", szCensimento);
logger.debug("Category: %s", szCategoria);
db = new DBManager(szCensimento, Const.DB_USER, Const.DB_PASS);
if(db.connect())
{
String szQuery = String.format(Query.classes, szCategoria, szCategoria);
aClasses = db.query(szQuery);
db.disconnect();
}
try {
out = response.getWriter();
jsonEncode(aClasses, out);
} catch(IOException e) {
e.printStackTrace();
logger.error("Failed to encode JSON: %s", e);
}
logger.exit();
}
private void jsonEncode(ArrayList<HashMap<String,String>> aData, PrintWriter out)
{
HashMap<String,Object> result = new HashMap<String,Object>();
result.put("results", aData);
result.put("success", true);
Gson gson = new GsonBuilder().create();
gson.toJson(result, out);
}
}
If the webapp would use only one database, it could be rewritten as a Singleton, but in this way I have no idea on how to handle different connections for different databases.
How can avoid these exceptions?
The problem was that the connection object was declared as member.
Moving the variable inside the methods resolved.
I have created a RESTFUL webservice, witch returns a json, but at this time i only consult and show a simple select * , i need to create a complete CRUD solution, if anyone have some samples to share, i'll appreciate.
Best Regards to all
My code until now are:
DAO - Access.java
package dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import dto.Usuarios;
public class Access
{
public ArrayList<Usuarios> getUsuarios(Connection con) throws SQLException
{
ArrayList<Usuarios> usuariosList = new ArrayList<Usuarios>();
PreparedStatement stmt = con.prepareStatement("SELECT * FROM usuarios");
ResultSet rs = stmt.executeQuery();
try
{
while(rs.next())
{
Usuarios usuariosObj = new Usuarios();
usuariosObj.setUsr_id(rs.getInt("usr_id"));
usuariosObj.setUsr_login(rs.getString("usr_login"));
usuariosObj.setUsr_pwd(rs.getString("usr_pwd"));
usuariosList.add(usuariosObj);
}
} catch (SQLException e)
{
e.printStackTrace();
}
return usuariosList;
}
}
DTO - Usuarios.java
package dto;
public class Usuarios
{
private int usr_id;
private String usr_login;
private String usr_pwd;
public Usuarios()
{
}
public Usuarios(int usr_id, String usr_login, String usr_pwd)
{
super();
this.usr_id = usr_id;
this.usr_login = usr_login;
this.usr_pwd = usr_pwd;
}
public int getUsr_id()
{
return usr_id;
}
public void setUsr_id(int usr_id)
{
this.usr_id = usr_id;
}
public String getUsr_login()
{
return usr_login;
}
public void setUsr_login(String usr_login)
{
this.usr_login = usr_login;
}
public String getUsr_pwd()
{
return usr_pwd;
}
public void setUsr_pwd(String usr_pwd)
{
this.usr_pwd = usr_pwd;
}
#Override
public String toString()
{
return "[ {usr_id=" + usr_id + ", usr_login=" + usr_login + ", usr_pwd=" + usr_pwd + "} ]";
}
}
Model - AccessManager.java
package model;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import dao.Access;
import dao.Database;
import dto.Usuarios;
public class AccessManager
{
public ArrayList<Usuarios> getUsuarios() throws Exception
{
ArrayList<Usuarios> usuariosList = new ArrayList<Usuarios>();
Database db = new Database();
Connection con = db.getConnection();
Access access = new Access();
usuariosList = access.getUsuarios(con);
return usuariosList;
}
}
WebService - UsuariosService.java
package webService;
import java.util.ArrayList;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import com.google.gson.Gson;
import model.AccessManager;
import dto.Usuarios;
#Path("/UsuariosService")
public class UsuariosService
{
#GET
#Path("/usuarios")
#Produces("application/json")
public String usuarios()
{
String usuarios = null;
ArrayList<Usuarios> usuariosList = new ArrayList<Usuarios>();
try
{
usuariosList = new AccessManager().getUsuarios();
Gson gson = new Gson();
//usuarios = gson.toJson(usuariosList);
usuarios = "{\"usuarios\" :" + gson.toJson(usuariosList) + "}";
} catch (Exception e)
{
e.printStackTrace();
}
return usuarios;
}
}
Usually you should ask a specific trouble you have instead of ask for samples. It looks like you have a structured code and all you need is implement all operations exposing as a service.
In case you need a sample, there quite a lot of resources on the web. Something like this: https://code.google.com/p/javaee6-crud-example/
I'll try give you some quick tips below:
WebService - UsuariosService.java
#POST
#Path("/usuarios")
public Response save(Usuario user) {
try {
manager= new AccessManager();
manager.save(user);
return Response.ok("User has been created.").build();
} catch (Exception e) {
e.printStackTrace();
}
return usuarios;
}
#DELETE
#Path("/usuarios/{id}")
public Response delete(#PathParam("id") String id) {
try {
manager= new AccessManager();
manager.delete(id);
return Response.ok("User has been deleted.").build();
} catch (Exception e) {
e.printStackTrace();
}
return usuarios;
}
#PUT
#Path("/usuarios/{id}")
public Response delete(#PathParam("id") String id, Usuario user) {
try {
manager= new AccessManager();
manager.update(id, user);
return Response.ok("User has been updated.").build();
} catch (Exception e) {
e.printStackTrace();
}
return usuarios;
}
If you donĀ“t understand the usage of PUT, DELETE, POST and so on, I recommend you to read HTTP Method Tutorial. There is several discussion regarding this but you might skip it for a while.
I think you might get an idea from here. Your DAO needs to implement methods to perform CRUD interface as well. The link I've added has a very simple sample that might help as well. You might also check this JPA link.
Not sure whether info above helped but I think it is a start since you have to code it in order to understand more about it :)
I'm trying to use the #PathParam using Jersey, but it always sees it as null.
Here's the method:
The url is http://localhost:8080/GiftRegistryAPI/api/v2/inventory/david with /v2/inventory being at the class level
package com.omar.rest.inventory;
import javax.websocket.server.PathParam;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Request;
import javax.ws.rs.core.Response;
import org.codehaus.jettison.json.JSONArray;
import com.omar.rest.util.*;
#Path("/v2/inventory")
public class V2_Inventory {
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response returnHostRegistries(#QueryParam("hostId") int hostId) throws Exception {
String returnString = null;
JSONArray jsonArray = new JSONArray();
try {
// A host ID of 0 indicates a null parameter, there will never be a host with an ID of 0
if (hostId == 0) {
return Response.status(400).entity("Error: please provide a valid host ID for this search").build();
}
Schema dao = new Schema();
jsonArray = dao.qryReturnHostRegistries(hostId);
returnString = jsonArray.toString();
}
catch (Exception e) {
e.printStackTrace();
return Response.status(500).entity("Server was not able to process your request").build();
}
System.out.println(returnString);
return Response.ok(returnString).build();
}
#Path("/{firstName}")
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response returnSearchedRegistries(#PathParam("firstName") String name) throws Exception{
String returnString = null;
JSONArray jsonArray = new JSONArray();
System.out.println("Name: " +name);
try {
Schema dao = new Schema();
jsonArray = dao.qryReturnHostRegistries(name);
returnString = jsonArray.toString();
}
catch (Exception e) {
e.printStackTrace();
return Response.status(500).entity("Server was not able to process your request").build();
}
System.out.println(returnString);
return Response.ok(returnString).build();
}
}
The name parameter when debugged is always null, and I can't find any way at all of getting it to recognise I've entered anything in.
Any ideas what might be going wrong?
It was my import statement
import javax.websocket.server.PathParam;
should have been
import javax.ws.rs.PathParam;
In this error, most of the time the issue is wrong import. Just make sure you have import javax.ws.rs.PathParam;
I am trying to parse a json file with JSONParse and am getting this error, with the error occurring in beginning of the following json:
Unexpected token COLON(:) at position 11.
{"276716878": {
"followers": [
2435018580,
1664252310,
372262434
],
"following": [
16211434,
945440959,
130682467,
264257750,
900526363,
318231688,
40335029,
64044676
]
}}
I also wrote the json file with the following:
FileWriter out = new FileWriter(JSON_FILE);
out.write(json.toString(1));
out.flush();
out.close();
There could be some format error in the json string you passed. Validate your json string. The below sample code works fine.
import java.io.FileWriter;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.json.JSONException;
import org.json.JSONObject;
public class Test {
private static final Logger logger = Logger.getLogger(Test.class.getName());
private static final String JSON_FILE = "/home/visruth/Desktop/Visruth.txt";
public static void main(String[] args) {
String jsonText = "{\"215876567\": { \"followers\": [ 2464054938, 772677937]}}";
try (
FileWriter out = new FileWriter(JSON_FILE);
) {
JSONObject json = new JSONObject(jsonText);
int indentFactor = 1;
String prettyprintedJSON = json.toString(indentFactor);
System.out.println(prettyprintedJSON);
out.write(prettyprintedJSON);
} catch (JSONException e) {
logger.log(Level.SEVERE, e.getMessage());
} catch (IOException e) {
logger.severe(e.getMessage());
}
}
}
Assign your json text in jsonText variable and try.
I think you are referring classes from different apis for this purpose. Just use only one api.
Here is a demo code which works fine with the given json string in the question.
import java.io.FileWriter;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.junit.Assert;
import org.junit.Test;
public class TestCase {
private static final String JSON_FILE = "/home/visruth/Desktop/Visruth.txt";
#Test
public void testJSONParser() throws Exception {
JSONParser parser = new JSONParser();
try (
FileWriter out = new FileWriter(JSON_FILE);
) {
String jsonText = "{\"276716878\": { \"followers\": [ 2435018580, 1664252310, 372262434 ], \"following\": [ 16211434, 945440959, 130682467, 264257750, 900526363, 318231688, 40335029, 64044676 ] }}";
Object obj = parser.parse(jsonText);
JSONObject jsonObject = (JSONObject) obj;
JSONObject jsonObject215876567 = (JSONObject)jsonObject.get("276716878");
JSONArray followers = (JSONArray)(jsonObject215876567.get("followers"));
Assert.assertEquals("[2435018580,1664252310,372262434]", followers.toString());
String jsonStringFromJsonObject = jsonObject.toString();// There is no argument as an int
out.write(jsonStringFromJsonObject);
} catch (ParseException e) {
Assert.fail(e.getMessage());
}
}
}