in the RESTController of a Spring Boot Application I retrieve a requestBody as JSON which looks like this:
{id=-1, name=test, street=test, houseNumber=1, postalCode=66111, city=Saarbrücken, sleepingSpots=2, unavailableDates=[2022-06-29 00:00:00.000, 2022-06-30 00:00:00.000]}
I want to create a couch object with the values from this json string, so I try to call constructor and pass the values like this:
new Couch(requestBody.get("name"),..., Integer.parseInt(requestBody.get("postalCode")), ...)
So far, it works fine.
Trouble begins with unavailableDates. Class Couch has attribute:
List<LocalDate> unavailabeDates;
So I try to create a LocalDate object for each date which is inside unavailabeDate part of the json request.
Can you help me to do so?
CodePudding user response:
The string you showed is not JSON. JSON would look like:
{
"id"=-1, "name"="test"
}
For example - quotes around strings. I'm guessing you are getting real JSON, throwing it through a crappy JSON parsing library you should not be using (such as org.json
) that turned it into a Map<String, Object>
, and you then called .toString()
on that.
So, immediate step 1: Search the web for a tutorial on Jackson or GSON, these are JSON parsing libraries you want to use. These 'unmarshall' JSON into a class you make, so, you make a java class that looks like this data, i.e.:
class WhateverThisIs {
int id;
String name;
List<LocalDate> unavailableDates;
}
and in many ways your problem is already solved.
There is a slight weirdness going on here - whatever is making this data is confused about date handling. That's more or less normal, virtually all programming languages are rather fundamentally broken. Java, fortunately, isn't, since Java8 and the introduction of the java.time
package (java.util.Date
, and java.util.Calendar
are worthless, don't use those).
At any rate, having 00:00:00
in a date string that is not supposed to represent time in the first place is problematic, a JSON unmarshaller will probably not silently just assume that those zeroes can be ignored. You can trivially make your own code that turns those strings into a LocalDate, and you can strip the dates off.
If you really, really do not want to use unmarshalling JSON libraries for some crazy reason, note that your input is most likely a List<String>
then, with the list always having 2 dates (the start and the end one). You can turn a string into a LocalDate (the right datatype for what this data is representing) as follows:
private static final DateTimeFormatter MY_DATE_FORMAT = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS");
public LocalDate String parse(String in) {
var ldt = LocalDateTime.parse(in, MY_DATE_FORMAT);
return ldt.toLocalDate();
}
// example:
parse("2022-06-29 00:00:00.000");
You can use the same code if you're writing custom unmarshalling code to turn that string into the requisite LocalDate
.
CodePudding user response:
I try to explain more exactly:
This is the method in my controller:
@ResponseBody
@PostMapping(value = "/couch", consumes = { MediaType.APPLICATION_JSON_VALUE }, produces = {MediaType.APPLICATION_JSON_VALUE })
@ResponseStatus(code = HttpStatus.OK)
public CouchDto postCouch(@RequestBody Map<String, String> requestBody) {
LOGGER.info("POST /couch was called with request body: " requestBody);
return newCouch = SERVICE.createCouch(
requestBody.get("name"),
requestBody.get("street"),
requestBody.get("houseNumber"),
Integer.parseInt(requestBody.get("postalCode")),
requestBody.get("city"),
Integer.parseInt(requestBody.get("sleepingSpots")),
requestBody.get("unavailableDates"), // here I want to pass List<LocalDate>, maybe List<LocalDateTime>
Integer.parseInt(requestBody.get("owner")));
}
requestBody contains the following "JSON" (I know this is just a String that looks simular to JSON, but this is what I get from HTTP Request from a Flutter app...):
{id=-1, name=Testcouch, street=Test, houseNumber=1, postalCode=123456, city=test, sleepingSpots=2, unavailableDates=[2022-06-29 00:00:00.000, 2022-06-30 00:00:00.000], owner=1}
I'm able to pass all values to the constructor by calling requestBody.get("value"). Sometime I have to parse it to an integer, like postalCode or owner.
But when I try to create date objects, it is not possible because:
requestBody.get("unavailableDates")
delivers a string like this:
"[2022-06-29 00:00:00.000, 2022-06-30 00:00:00.000]"
What I need to create a LocalDateTime object is a List like:
["2022-06-29 00:00:00.000", "2022-06-30 00:00:00.000"]
With that I can easily loop over all list entries and create the objects... But I don't know how to get there...
CodePudding user response:
As you said in the comments:
I'm not having a list yet: I have a string like this: "[2022-06-29 00:00:00.000, 2022-06-30 00:00:00.000]" and looking for a way to convert it into a List like this: ["2022-06-29", "2022-06-30"] –
By the given example
First thing to do is to remove brackets: [2022-06-29 00:00:00.000, 2022-06-30 00:00:00.000]
-> 2022-06-29 00:00:00.000, 2022-06-30 00:00:00.000
Then split it by ,
to get an array of: 2022-06-29 00:00:00.000
, 2022-06-30 00:00:00.000
and stream over it.
Trim redundant white spaces: 2022-06-30 00:00:00.000
-> 2022-06-30 00:00:00.000
Split each datetime by white space
to separate date from time and get index 0 of it because date is first thing before whitespace
At the collect it as an array of dates that we wanted in first place.
import java.util.Arrays;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
String timestamps = "[2022-06-29 00:00:00.000, 2022-06-30 00:00:00.000]";
timestamps = removeBrackets(timestamps);
List<String> timestampsInList = Arrays.stream(timestamps.split(","))//
.map(String::trim)// Remove first and last white spaces.
.map(datetime -> datetime.split(" ")[0])// Split datetime by white space to separate date from time
.collect(Collectors.toList());
System.out.println(timestampsInList);
}
public static String removeBrackets(String str) {
// Removing first and last character
// of a string using substring() method
return str.substring(1, str.length() - 1);
}
}
The output will be:
[2022-06-29, 2022-06-30]
CodePudding user response:
Sure. This is the service class where a couch object should be created:
...
private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSSS");
...
//""""""""""""""""""""""" Couch functionality """"""""""""""""""""""""""""""//
public CouchDto createCouch(String name, String street, String houseNumber, int postalCode, String city,
int sleepingSpots, String unavailableDates, int owner) {
return new CouchDto(name, street, houseNumber, postalCode, city, sleepingSpots, this.getDateList(unavailableDates), owner);
}
private List<LocalDateTime> getDateList(String unavailableDates) {
unavailableDates = this.removeBrackets(unavailableDates);
List<String> unavailableDatesInStringList = Arrays.stream(unavailableDates.split(",")).map(String::trim)
.map(datetime -> datetime.split(" ")[0])// Split datetime by white space to separate date from time
.collect(Collectors.toList());
System.out.println(unavailableDatesInStringList);
List<LocalDateTime> unavailabeDateList = new ArrayList<>();
for (String date : unavailableDatesInStringList) {
unavailabeDateList.add(LocalDateTime.parse(date, DATE_FORMAT));
}
return unavailabeDateList;
}
private String removeBrackets(String str) {
return str.substring(1, str.length() - 1);
}
When createCouch gets triggered the following error occurs:
2022-06-25 20:34:21.219 ERROR 7984 --- [nio-8080-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.time.format.DateTimeParseException: Text '2022-06-28 00:00:00.000' could not be parsed, unparsed text found at index 19] with root cause
java.time.format.DateTimeParseException: Text '2022-06-28 00:00:00.000' could not be parsed, unparsed text found at index 19