How to insert a json data into postgresql using database function cal without create entity model(getter and setter) in spring boot - spring-boot

I am new to spring java. I have a controller class and repository class. what I actually want is to insert a json data into postgresql database by calling a database function(stored procedure)and return a json data as response.It shows that BAD SQL Grammar Error. Please help me to solve the issue...I am sharing my code. I am getting error in the
Map<String, Object> result =insertSurveyCall.execute(params); line.
UserController.java
#RequestMapping(value="/savedbData", method = RequestMethod.POST, produces="application/json;charset=utf-8")
public String uploadFile(#RequestParam String data,HttpServletRequest request, HttpServletResponse response) throws SQLException
{
JSONObject requestJSON= new JSONObject(data);
String result="";
result=userRepository.saveDatahouse(requestJSON);
return result.toString();
}
UserRepository.java
public interface UserRepository {
String saveDatahouse( JSONObject requestJSON) throws SQLException;
}
UserRepositoryImpl.java
#Override
public String saveDatahouse(JSONObject requestJSON) throws SQLException {
JSONObject dbdata = requestJSON;
JSONObject resultJSON = new JSONObject();
Map<String, Object> params = new HashMap<String, Object>();
String reult="";
try {
PGobject pObj = new PGobject();
pObj.setType("json");
pObj.setValue(dbdata.toString());
SimpleJdbcCall insertSurveyCall = new SimpleJdbcCall(jdbcTemplate).withFunctionName("add_data_to_db");
params.put("params", pObj);
Map<String, Object> result =insertSurveyCall.execute(params);
System.out.println("result at repository::::::::::::::::::::::::");
return resultJSON.toString();
} catch (IncorrectResultSizeDataAccessException e) {
return null;
}
}

Related

How to handle response codes in RestTemplate without catching exceptions? [Spring Boot]

I'm sending a response to another web service to create an user. If the user already exists it sends back the 409 response. I'm using RestTemplate like so:
#PostMapping("/todos/{toDoNoteId}/users")
public ResponseEntity <String> postUser(#RequestBody User user, #PathVariable int toDoNoteId, UriComponentsBuilder builder)throws HttpMessageNotReadableException, ParseException{
RestTemplate restTemplate = new RestTemplate();
final String uri = "http://friend:5000/users";
try {
ResponseEntity<String> result = restTemplate.postForEntity(uri, user, String.class);
return result;
}
catch (HttpClientErrorException ex) {
return ResponseEntity.status(ex.getRawStatusCode()).headers(ex.getResponseHeaders())
.body(ex.getResponseBodyAsString());
}
}
While catching an exception somewhat works (in the catch block i can access the status code and body), is there a way to access it without exceptions something similar like this:
#PostMapping("/todos/{toDoNoteId}/users")
public ResponseEntity <String> postUser(#RequestBody User user, #PathVariable int toDoNoteId, UriComponentsBuilder builder)throws HttpMessageNotReadableException, ParseException{
RestTemplate restTemplate = new RestTemplate();
final String uri = "http://friend:5000/users";
ResponseEntity<String> result = restTemplate.postForEntity(uri, user, String.class);
if(result.getStatusCode()=="409"){
// do something
}
else{
// do something else
}
return result;
}
Have you been check the ExceptionHandler? When exception throws, ExceptionHandler handles it.
For example:
#ControllerAdvice()
public class CustomExceptionHandler {
private static final Logger logger = LogManager.getLogger("CustomExceptionHandler");
#ExceptionHandler(YourException.class)
public ResponseEntity handleYourException(HttpServletRequest request, YourException ex) {
return ResponseEntity.ok("");
}
#ExceptionHandler(Exception.class)
public ResponseEntity handleException(HttpServletRequest request, Exception ex) {
logExp("Exception", request, ex);
//return new ResponseEntity<>();
return null;
}
}
You can create your own custom resttemplate and define exception handler. Here is a code snippet.
#Configuration
public class CustomRestTemplate extends RestTemplate {
#Autowired
private CustomErrorHandler customErrorHandler;
#PostConstruct
public void init() {
this.setErrorHandler(customErrorHandler);
}
}
#Component
public class CustomErrorHandler implements ResponseErrorHandler {
#Override
public boolean hasError(ClientHttpResponse response) throws IOException {
if(response.getStatusCode() != "409"){
return true;
}else {
return false;
}
}
#Override
public void handleError(ClientHttpResponse response) throws IOException {
String responseBody = response.getBody();//Pls read from InputStream and create write into String
JSONObject jsonObj = new JSONObject(result);
JSONArray jsonArray = new JSONArray();
jsonObj.put("status", response.getStatusCode());
jsonObj.put("body", responseBody );
jsonArray.put(jsonObj);
responseString = jsonArray.get(0).toString();
throw new MyException(responseString );
}
}
class MyException throw RuntimeException {
public MyException (String message) {
super(message);
}
}
So, your class will changed to
#PostMapping("/todos/{toDoNoteId}/users")
public ResponseEntity <String> postUser(#RequestBody User user, #PathVariable int toDoNoteId, UriComponentsBuilder builder)throws HttpMessageNotReadableException, ParseException{
CustomRestTemplate restTemplate = new CustomRestTemplate ();
final String uri = "http://friend:5000/users";
ResponseEntity<String> result = restTemplate.postForEntity(uri, user, String.class);
return result
}

Get HTTP request parameters in Spring HTTPMessageConverter

I am using Spring's AbstractHttpMessageConverter to allow me instantiate my own object.
Converter
public class PaypalIPNHttpMessageConverter extends AbstractHttpMessageConverter<IPNMessage> {
public PaypalIPNHttpMessageConverter() {
super(MediaType.APPLICATION_FORM_URLENCODED, MediaType.TEXT_PLAIN);
}
#Override
protected boolean supports(Class<?> clazz) {
return clazz == IPNMessage.class;
}
#Override
protected IPNMessage readInternal(Class<? extends IPNMessage> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
//Converts HTTPRequest into map<string,string> that IPNMessage can then parse
String requestString = IOUtils.toString(inputMessage.getBody(), "UTF-8");
Map<String, String[]> requestMap = new LinkedHashMap<>();
for (String keyValue : requestString.split("&")) { //each key value is delimited by &
String[] pairs = keyValue.split("=", 2); // = pairs a key to a value
requestMap.put(pairs[0], pairs[1].split(",")); // , splits multiple values for that key
}
return new IPNMessage(requestMap);
}
#Override
protected void writeInternal(IPNMessage ipnMessage, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
}
}
In readINternal(), I am passed a HttpInputMessage object, which only has getBody() function that produces an InputStream of the HTTPRequest.
I have tried to write my own code to parse and build a ParameterMap but it does not always work if the urlencoding is different.
Is there anyway I can get Spring's WebRequest or HttpServletRequest object from the converter and use there wonderful getParameterMap() function?
TL;DR
Is there anyway to use WebRequest or HTTPServletRequest in the MessageConverter instead of HttpInput so I can use the wonderful getParameterMap() function, instead of reinventing the wheel?
Thanks
Look at how it is implemented in Spring FormHttpMessageConverter. It tokenizes request parameter using & just like your solution. However it dtermines the charset to use from the Content-Type request header if provided. Otherwise it uses default UTF-8
//extract from FormHttpMessageConverter
public MultiValueMap<String, String> read(Class<? extends MultiValueMap<String, ?>> clazz,
HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
MediaType contentType = inputMessage.getHeaders().getContentType();
Charset charset = (contentType.getCharSet() != null ? contentType.getCharSet() : this.charset);
String body = StreamUtils.copyToString(inputMessage.getBody(), charset);
String[] pairs = StringUtils.tokenizeToStringArray(body, "&");
MultiValueMap<String, String> result = new LinkedMultiValueMap<String, String>(pairs.length);
for (String pair : pairs) {
int idx = pair.indexOf('=');
if (idx == -1) {
result.add(URLDecoder.decode(pair, charset.name()), null);
}
else {
String name = URLDecoder.decode(pair.substring(0, idx), charset.name());
String value = URLDecoder.decode(pair.substring(idx + 1), charset.name());
result.add(name, value);
}
}
return result;
}
You can simply get the current request using the following code
HttpServletRequest httpRequest = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();

Spring Resful Client with RestTemplate

I'm using RestTemplate class to get All user but when i run Main in Client then occur error, i don't know why ???
Exception in thread "main" java.lang.ClassCastException:
java.util.LinkedHashMap cannot be cast to
edu.java.spring.service.user.model.User at
edu.java.spring.service.client.RestClientTest.main(RestClientTest.java:33)
Here file RestClientTest.java
public class RestClientTest {
public static void main(String[] args) throws IOException{
List<User> users = getUsers();
for (int i = 0; i < users.size(); i++) {
System.out.println("Rest Response" + loadUser(users.get(i).getUserName()));
}
}
public static List<User> getUsers(){
String uri = new String("http://localhost:8080/rest/user/list");
RestTemplate rt = new RestTemplate();
return (List<User>) rt.getForObject(uri,List.class);
}
public static String loadUser(String username) throws IOException {
String url = "http://localhost:8080/rest/user/json/" + username;
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("Accept", "application/json");
InputStream stream = con.getInputStream();
BufferedReader in = new BufferedReader(new InputStreamReader(stream));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
return response.toString();
}
Here file UserRestServiceController.java
#Controller
public class UserRestServiceController {
#Autowired
public UserDao userDao;
#Autowired
public View jsonTemplate;
#RequestMapping(value = "/rest/user/list", produces = MediaType.APPLICATION_JSON_VALUE,method = RequestMethod.GET)
public #ResponseBody List<User> getUsers(){
return userDao.listUsers();
}
#RequestMapping(value="/rest/user/json/{username}")
public ModelAndView loadUser(#PathVariable("username")String name){
return new ModelAndView(jsonTemplate,"data",userDao.loadUser(name));
}
I believe the following method is not returning as you expect:
rt.getForObject(uri,List.class);
Take a look at this question as it might help you also fix your error.
ClassCastException: RestTemplate returning List instead of List

How to test spring rest operation exchange

I have a problem with test of my method which use RestOperation exchange method. When i'm trying to mock response i get an error:
ResponseEntity cannot be returned by toString()
toString() should return String
***
If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
1. This exception *might* occur in wrongly written multi-threaded tests.
Please refer to Mockito FAQ on limitations of concurrency testing.
2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
- with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.
org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
Below is my class, which i want to test
#Component
public class AuthGateway {
#Autowired
AuthorizedHttpEntityFactory authorizedHttpEntityFactory;
#Autowired
RestOperations restOperations;
#Value("${authServer.host}:${authServer.port}/${authServer.validateToken.path}")
private String authPath;
#Value("${authServer.host}:${authServer.port}/basic/check")
private String basicAuthPath;
#Value("${authServer.tokenName}")
private String tokenName;
#Value("${authServer.host}:${authServer.port}/user")
private String userProfileUrl;
#Value("${authServer.host}:${authServer.port}/homeowner")
private String homeownerUrl;
public UnpackedToken authenticate(String token) throws ResourceAccessException, AuthException {
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add(tokenName, token);
HttpEntity httpEntity = authorizedHttpEntityFactory.getAuthorizedHttpEntity(formData);
Map map = null;
try {
ResponseEntity<Map> entity = restOperations.exchange(authPath, HttpMethod.POST,
httpEntity, Map.class);
map = entity.getBody();
} catch (RestClientException e) {
processError(e);
}
#SuppressWarnings("unchecked")
Map<String, Object> result = map;
return new UnpackedToken(result);
}
and Test class
#RunWith(MockitoJUnitRunner.class)
public class AuthGatewayTest {
private ResponseEntity<Map> entity;
#Mock
private RestOperations restOperations;
#Mock
private LinkedMultiValueMap linkedMultiValueMap;
#Mock
private AuthorizedHttpEntityFactory authorizedHttpEntityFactory;
#Autowired
#InjectMocks
private AuthGateway authGateway;
private String token;
private Integer userId = 1;
private String role = "ROLE_PRO";
private UnpackedToken unpackedToken;
private Map<String, Object> map;
private RestClientException restClientException;
private AuthException authException;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
restClientException = new RestClientException("Test exception");
authException = new AuthException("Test exception");
token = "token-token";
map = new HashMap<>();
map.put("UserId", userId);
map.put("authorities", Collections.singletonList(role));
entity = new ResponseEntity<>(map, HttpStatus.OK);
unpackedToken = new UnpackedToken(map);
}
#Test
public void testAuthenticateSuccessfully() throws Exception {
HttpEntity httpEntity = new HttpEntity("body");
Mockito.when(authorizedHttpEntityFactory.getAuthorizedHttpEntity(any(Map.class))).thenReturn(httpEntity);
Mockito.when(restOperations.exchange(
Mockito.anyString(), Mockito.<HttpMethod>any(), Mockito.<HttpEntity<?>>any(), Mockito.<Class<Map>>any())).
thenReturn(entity);
Mockito.doNothing().when(linkedMultiValueMap).add(any(), any());
assertEquals(this.unpackedToken, authGateway.authenticate(token));
}
What is wrong with this mock?
Weird, when i change mock line into:
Mockito.when(restOperations.exchange(
Mockito.anyString(), Mockito.<HttpMethod>any(), Mockito.<HttpEntity<?>>any(), Mockito.<Class<Map>>any())).
thenReturn(new ResponseEntity<>(map, HttpStatus.OK));
then it starts working properly...

How to use #ResponseBody to return a map<string, string>?

public class RestfulControllerImpl implements RestfulController {
#Override
#RequestMapping(value = "maptest", method = RequestMethod.GET)
#ResponseBody
public Object mapReturn() {
HashMap<String, String> map = new HashMap<String, String>();
map.put("name", "test1");
map.put("sex", "male");
map.put("address", "1324");
map.put("old", "123");
return map;
}
}
I want to return a map<string, string> for the request, and it occurs
HTTP-406 not acceptable
How to implement the method to return a response body with a map and it shows in like a json object?
If your Controller only return json (REST API) then annotate Class with #RestController instead of #Controller. Then you don't need to add #ResponseBody annotation to each and every Endpoint. Since we cleared the problem with missing #ResponseBody Below code will do what you want.
#GetMapping("/maptest")
public ResponseEntity<?> mapReturn() {
HashMap<String, String> map = new HashMap<String, String>();
map.put("name", "test1");
map.put("sex", "male");
map.put("address", "1324");
map.put("old", "123");
return ResponseEntity.ok(map);
}
Here ResponseEntity is wrapper for Http response. Since I declared here as ResponseEntity<?> I can return any Object as json. (It is good when you have return error response as another object) But if you sure that it will only return Map Object you can write it as ResponseEntity<Map> (If you have separate error handler)
Hope this is clear.
#RequestMapping(value = "maptest", method = RequestMethod.GET)
public ResponseEntity<?> mapReturn() {
HashMap<String, String> map = new HashMap<String, String>();
map.put("name", "test1");
map.put("sex", "male");
map.put("address", "1324");
map.put("old", "123");
return new ResponseEntity(map, HttpStatus.OK); // you can change status code based on response
}
You can set up ResponseEntity details such as body, status or headers.
4XX is client side error
try add request headers
Accept:application/json
"HTTP-406 not acceptable" mostly deals with content negotiation you can also check headers in the browser when you face this kind of problem, solution can be obtained using Jackson or Gson Dependency
Client Side
var jsonData = '{"name":"John", "age":30, "city":"New York"}'
var obj = JSON.parse(jsonData);
$.ajax({
type : "POST",
url : "${pageContext.request.contextPath}/getJSON",
dataType: 'json',
cache:false,
async:false,
data : obj,
success: function(data){
console.log(data.name);
console.log(data.gender);
console.log(data.address);
}
});
Server Side:
#RequestMapping(value="/getJSON")
#ResponseBody
public String mapReturnUsingJackson() throws JsonGenerationException, JsonMappingException, IOException {
Map<String, String> hashMap = new HashMap<String, String>();
hashMap.put("name", "County");
hashMap.put("address", "Unknown");
hashMap.put("gender", "male");
String jsonJackson=new ObjectMapper().writeValueAsString(hashMap);
return jsonJackson;
}
//OR
#RequestMapping(value="/getJSON")
#ResponseBody
public String mapReturnUsingGSON() {
Map<String, String> hashMap = new HashMap<String, String>();
hashMap.put("name", "County");
hashMap.put("address", "Unknown");
hashMap.put("gender", "male");
String jsonStr = new Gson().toJson(hashMap);
return jsonStr;
}
Return map instead of object.
#RequestMapping(value = "maptest", method = RequestMethod.GET)
#ResponseBody
public Map<String,String> mapReturn() {
HashMap<String, String> map = new HashMap<String, String>();
map.put("name", "test1");
map.put("sex", "male");
map.put("address", "1324");
map.put("old", "123");
return map;
}
Try changing the return type of the function to Map<String, String> and adding "produces" to the request mapping:
#RequestMapping(path="maptest", method=RequestMethod.GET, produces=MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public Map<String, String> test() {
Map<String, String> map = new HashMap<>();
map.put("key1", "value1");
map.put("key2", "value2");
return map;
}
#ResponseBody is use for returning string/json. You might wanted to use model, have a look at this
http://docs.spring.io/spring-framework/docs/2.5.x/api/org/springframework/ui/Model.html

Resources