-
Notifications
You must be signed in to change notification settings - Fork 207
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Change date/time format to ISO8601 on JSON serialization #548
Changes from 4 commits
46d240d
e635b2d
a1b646c
2c1f7ca
e65d711
d2ee00b
d20a4ad
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package br.com.caelum.vraptor.serialization.gson.adapters.iso8601; | ||
|
||
import java.lang.reflect.Type; | ||
import java.text.ParseException; | ||
import java.util.Calendar; | ||
|
||
import br.com.caelum.vraptor.converter.ConversionError; | ||
import br.com.caelum.vraptor.util.ISO8601Util; | ||
|
||
import com.google.gson.JsonDeserializationContext; | ||
import com.google.gson.JsonDeserializer; | ||
import com.google.gson.JsonElement; | ||
import com.google.gson.JsonParseException; | ||
|
||
public class CalendarDeserializer implements JsonDeserializer<Calendar> { | ||
|
||
public Calendar deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { | ||
|
||
try { | ||
String value = json.getAsString(); | ||
|
||
Calendar calendar = ISO8601Util.toCalendar(value); | ||
|
||
return calendar; | ||
} catch (ParseException e) { | ||
throw new ConversionError("Error to convert Calendar: " + e.getMessage()); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package br.com.caelum.vraptor.serialization.gson.adapters.iso8601; | ||
|
||
import java.lang.reflect.Type; | ||
import java.util.Calendar; | ||
|
||
import br.com.caelum.vraptor.util.ISO8601Util; | ||
|
||
import com.google.gson.JsonElement; | ||
import com.google.gson.JsonPrimitive; | ||
import com.google.gson.JsonSerializationContext; | ||
import com.google.gson.JsonSerializer; | ||
|
||
public class CalendarSerializer implements JsonSerializer<Calendar> { | ||
|
||
public JsonElement serialize(Calendar calendar, Type typeOfSrc, JsonSerializationContext context) { | ||
|
||
String json = ISO8601Util.fromCalendar(calendar); | ||
|
||
return new JsonPrimitive(json); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package br.com.caelum.vraptor.serialization.gson.adapters.iso8601; | ||
|
||
import java.lang.reflect.Type; | ||
import java.text.ParseException; | ||
import java.util.Date; | ||
|
||
import br.com.caelum.vraptor.converter.ConversionError; | ||
import br.com.caelum.vraptor.util.ISO8601Util; | ||
|
||
import com.google.gson.JsonDeserializationContext; | ||
import com.google.gson.JsonDeserializer; | ||
import com.google.gson.JsonElement; | ||
import com.google.gson.JsonParseException; | ||
|
||
public class DateDeserializer implements JsonDeserializer<Date> { | ||
|
||
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { | ||
|
||
try { | ||
String value = json.getAsString(); | ||
|
||
Date date = ISO8601Util.toDate(value); | ||
|
||
return date; | ||
} catch (ParseException e) { | ||
throw new ConversionError("Error to convert Date: " + e.getMessage()); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package br.com.caelum.vraptor.serialization.gson.adapters.iso8601; | ||
|
||
import java.lang.reflect.Type; | ||
import java.util.Date; | ||
|
||
import br.com.caelum.vraptor.util.ISO8601Util; | ||
|
||
import com.google.gson.JsonElement; | ||
import com.google.gson.JsonPrimitive; | ||
import com.google.gson.JsonSerializationContext; | ||
import com.google.gson.JsonSerializer; | ||
|
||
public class DateSerializer implements JsonSerializer<Date> { | ||
|
||
public JsonElement serialize(Date date, Type typeOfSrc, JsonSerializationContext context) { | ||
|
||
String json = ISO8601Util.fromDate(date); | ||
|
||
return new JsonPrimitive(json); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
|
||
/*** | ||
* Copyright (c) 2009 Caelum - www.caelum.com.br/opensource | ||
* All rights reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package br.com.caelum.vraptor.util; | ||
|
||
import java.text.ParseException; | ||
import java.text.SimpleDateFormat; | ||
import java.util.Calendar; | ||
import java.util.Date; | ||
import java.util.GregorianCalendar; | ||
import java.util.TimeZone; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
|
||
import javax.xml.datatype.DatatypeConfigurationException; | ||
|
||
/** | ||
* Helper class for handling ISO8601 strings of the following format: | ||
* "1982-06-10T05:00:00.000-03:00". It also supports parsing the "Z" timezone. | ||
* | ||
* @author Rafael Dipold | ||
*/ | ||
public final class ISO8601Util { | ||
|
||
/** Default Extended Format */ | ||
private static final String DEFAULT_ISO8601_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; | ||
|
||
private static final String REGEX_ISO8601 = "^(\\d{4})-?(\\d\\d)-?(\\d\\d)(?:T(\\d\\d)(?::?(\\d\\d)(?::?(\\d\\d)(?:\\.(\\d+))?)?)?(Z|([+-])(\\d\\d):?(\\d\\d)?)?)?$"; | ||
//1 2 3 4 5 6 7 8 9 10 11 | ||
|
||
/** SimpleDateFormat is not thread-safe, so give one to each thread */ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not create a new one every time? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd replace this thread local with a method which returns a configured SimpleDateFormat. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I make this way because the SimpleDateFormat is not thread-safe There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you create a new SimpleDateFormat every time, you won't have this problem. So, what you really should do is transform this ISO8601Util into a
And leave the thread control to the DI container. |
||
private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>() { | ||
protected SimpleDateFormat initialValue() { | ||
return new SimpleDateFormat(DEFAULT_ISO8601_FORMAT); | ||
} | ||
}; | ||
|
||
/** Transform Calendar to ISO8601 string. */ | ||
public static String fromCalendar(final Calendar calendar) { | ||
formatter.get().setTimeZone(calendar.getTimeZone()); | ||
return fromDate(calendar.getTime()); | ||
} | ||
|
||
/** Transform java.util.Date to ISO8601 string. */ | ||
public static String fromDate(final Date date) { | ||
String formatted = formatter.get().format(date); | ||
formatted = formatted.replaceAll("[+-]00:?00$", "Z"); | ||
return formatted; | ||
} | ||
|
||
/** Get current date and time formatted as ISO8601 string. */ | ||
public static String now() { | ||
return fromCalendar(GregorianCalendar.getInstance()); | ||
} | ||
|
||
/** Transform ISO8601 string to Calendar | ||
* @throws DatatypeConfigurationException */ | ||
public static Calendar toCalendar(final String iso8601String) throws ParseException { | ||
Pattern pattern = Pattern.compile(REGEX_ISO8601); | ||
Matcher matcher = pattern.matcher(iso8601String); | ||
|
||
if (matcher.matches()) { | ||
int year = matcher.group(1) != null ? Integer.valueOf(matcher.group(1)) : 0; | ||
int month = matcher.group(2) != null ? Integer.valueOf(matcher.group(2)) - 1 : 0; | ||
int day = matcher.group(3) != null ? Integer.valueOf(matcher.group(3)) : 0; | ||
|
||
int h = (matcher.group(4) != null ? Integer.valueOf(matcher.group(4)) : 0); | ||
int m = (matcher.group(5) != null ? Integer.valueOf(matcher.group(5)) : 0); | ||
int s = (matcher.group(6) != null ? Integer.valueOf(matcher.group(6)) : 0); | ||
int ms = Math.round(Float.parseFloat("0." + (matcher.group(7) != null ? matcher.group(7) : "0")) * 1000); | ||
|
||
TimeZone timeZone = TimeZone.getTimeZone("GMT" + (matcher.group(8) != null ? matcher.group(8) : "")); | ||
|
||
Calendar calendar = GregorianCalendar.getInstance(timeZone); | ||
calendar.set(Calendar.YEAR, year); | ||
calendar.set(Calendar.MONTH, month); | ||
calendar.set(Calendar.DAY_OF_MONTH, day); | ||
calendar.set(Calendar.HOUR_OF_DAY, h); | ||
calendar.set(Calendar.MINUTE, m); | ||
calendar.set(Calendar.SECOND, s); | ||
calendar.set(Calendar.MILLISECOND, ms); | ||
|
||
return calendar; | ||
} | ||
else | ||
throw new java.text.ParseException("Unparseable ISO8601 date format: " + iso8601String, 0); | ||
} | ||
|
||
/** Transform ISO8601 string to java.util.Date */ | ||
public static Date toDate(final String iso8601String) throws ParseException { | ||
Calendar calendar = toCalendar(iso8601String); | ||
return calendar.getTime(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be unnecessary. If these serializers are
@Component
s, it should work without these 4 lines.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But doesn´t work without this code, and I don´t know what I can do.
If exists classes
@Component adapters.CalendarSerializer
and@Component adapters.iso8601.CalendarSerializer
, the provider inject inList serializers
two instances of@Component adapters.CalendarSerializer
and no instance of@Component adapters.iso8601.CalendarSerializer
regardless of the web.xml package configuration being configured.Feel free to call me on the talk if necessary
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see your point =/
Maybe we could include and document a context-param which enables the iso8601 strategy, while using the
adapters.CalendarSerializer
...