Skip to content

Commit

Permalink
Merge pull request #548 from dipold/iso8601
Browse files Browse the repository at this point in the history
Change date/time format to ISO8601 on JSON serialization
  • Loading branch information
lucascs committed Jul 31, 2013
2 parents eaccb30 + d20a4ad commit b58965b
Show file tree
Hide file tree
Showing 13 changed files with 476 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package br.com.caelum.vraptor.deserialization.gson;

import java.util.Collections;
import java.util.List;

import br.com.caelum.vraptor.ioc.Component;
import br.com.caelum.vraptor.serialization.gson.PackageComparator;

import com.google.common.collect.Lists;
import com.google.gson.JsonDeserializer;

@Component
@SuppressWarnings("rawtypes")
public class DefaultJsonDeserializers implements JsonDeserializers {

private List<JsonDeserializer> deserializers;

public DefaultJsonDeserializers(List<JsonDeserializer> deserializers) {
this.deserializers = Lists.newArrayList(deserializers);

sortDeserializers();
}

public List<JsonDeserializer> getDeserializers() {
return deserializers;
}

/**
* Override this method if you want another ordering strategy.
*/
protected void sortDeserializers() {
Collections.sort(this.deserializers, new PackageComparator());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

Expand Down Expand Up @@ -48,9 +47,9 @@ public class GsonDeserialization implements Deserializer {

private final HttpServletRequest request;

public GsonDeserialization(ParameterNameProvider paramNameProvider, List<JsonDeserializer> adapters, HttpServletRequest request) {
public GsonDeserialization(ParameterNameProvider paramNameProvider, JsonDeserializers adapters, HttpServletRequest request) {
this.paramNameProvider = paramNameProvider;
this.adapters = adapters;
this.adapters = adapters.getDeserializers();
this.request = request;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package br.com.caelum.vraptor.deserialization.gson;

import java.util.List;

import com.google.gson.JsonDeserializer;

public interface JsonDeserializers {

@SuppressWarnings("rawtypes")
List<JsonDeserializer> getDeserializers();
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package br.com.caelum.vraptor.serialization.gson;

import java.util.Collections;
import java.util.List;

import br.com.caelum.vraptor.ioc.Component;
Expand All @@ -9,6 +10,7 @@
import com.google.gson.JsonSerializer;

@Component
@SuppressWarnings("rawtypes")
public class DefaultJsonSerializers implements JsonSerializers {

private static boolean isHibernateProxyPresent;
Expand All @@ -22,16 +24,22 @@ public class DefaultJsonSerializers implements JsonSerializers {
}
private List<JsonSerializer> serializers;

@SuppressWarnings("rawtypes")
public DefaultJsonSerializers(List<JsonSerializer> serializers) {
this.serializers = Lists.newArrayList(serializers);
if (isHibernateProxyPresent) {
if (isHibernateProxyPresent)
this.serializers.add(new HibernateProxySerializer());
}

sortSerializers();
}

public List<JsonSerializer> getSerializers() {
return serializers;
}


/**
* Override this method if you want another ordering strategy.
*/
protected void sortSerializers() {
Collections.sort(this.serializers, new PackageComparator());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package br.com.caelum.vraptor.serialization.gson;

import java.util.Comparator;

public final class PackageComparator implements Comparator<Object> {

private static final String CORE_ADAPTER = "br.com.caelum.vraptor.serialization.gson.adapters";
private static final String ISO8601_ADAPTER = "br.com.caelum.vraptor.serialization.iso8601.gson";

public int compare(Object o1, Object o2) {
return giveMorePriorityToISO8601Adapters(o1, o2);
}

private int giveMorePriorityToISO8601Adapters(Object o1, Object o2) {
String packageNameO1 = o1.getClass().getPackage().getName();
String packageNameO2 = o2.getClass().getPackage().getName();

if (packageNameO1.startsWith(CORE_ADAPTER) && packageNameO2.startsWith(ISO8601_ADAPTER))
return -1;

if (packageNameO1.startsWith(ISO8601_ADAPTER) && packageNameO2.startsWith(CORE_ADAPTER))
return 1;

return packageNameO1.compareTo(packageNameO2);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package br.com.caelum.vraptor.serialization.iso8601.gson;

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.ioc.Component;
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;

@Component
public class CalendarISO8601Deserializer implements JsonDeserializer<Calendar> {

private final ISO8601Util iso8601;

public CalendarISO8601Deserializer(ISO8601Util iso8601) {
this.iso8601 = iso8601;
}

public Calendar deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {

try {
String value = json.getAsString();

Calendar calendar = iso8601.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,29 @@
package br.com.caelum.vraptor.serialization.iso8601.gson;

import java.lang.reflect.Type;
import java.util.Calendar;

import br.com.caelum.vraptor.ioc.Component;
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;

@Component
public class CalendarISO8601Serializer implements JsonSerializer<Calendar> {

private final ISO8601Util iso8601;

public CalendarISO8601Serializer(ISO8601Util iso8601) {
this.iso8601 = iso8601;
}

public JsonElement serialize(Calendar calendar, Type typeOfSrc, JsonSerializationContext context) {

String json = iso8601.fromCalendar(calendar);

return new JsonPrimitive(json);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package br.com.caelum.vraptor.serialization.iso8601.gson;

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.ioc.Component;
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;

@Component
public class DateISO8601Deserializer implements JsonDeserializer<Date> {

private final ISO8601Util iso8601;

public DateISO8601Deserializer(ISO8601Util iso8601) {
this.iso8601 = iso8601;
}

public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {

try {
String value = json.getAsString();

Date date = iso8601.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,29 @@
package br.com.caelum.vraptor.serialization.iso8601.gson;

import java.lang.reflect.Type;
import java.util.Date;

import br.com.caelum.vraptor.ioc.Component;
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;

@Component
public class DateISO8601Serializer implements JsonSerializer<Date> {

private final ISO8601Util iso8601;

public DateISO8601Serializer(ISO8601Util iso8601) {
this.iso8601 = iso8601;
}

public JsonElement serialize(Date date, Type typeOfSrc, JsonSerializationContext context) {

String json = iso8601.fromDate(date);

return new JsonPrimitive(json);
}
}
104 changes: 104 additions & 0 deletions vraptor-core/src/main/java/br/com/caelum/vraptor/util/ISO8601Util.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@

/***
* 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 br.com.caelum.vraptor.ioc.Component;

/**
* 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
*/
@Component
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

private static final SimpleDateFormat formatter = new SimpleDateFormat(DEFAULT_ISO8601_FORMAT);

/** Transform Calendar to ISO8601 string. */
public String fromCalendar(final Calendar calendar) {
formatter.setTimeZone(calendar.getTimeZone());
return fromDate(calendar.getTime());
}

/** Transform java.util.Date to ISO8601 string. */
public String fromDate(final Date date) {
String formatted = formatter.format(date);
formatted = formatted.replaceAll("[+-]00:?00$", "Z");
return formatted;
}

/** Get current date and time formatted as ISO8601 string. */
public String now() {
return fromCalendar(GregorianCalendar.getInstance());
}

/** Transform ISO8601 string to Calendar
* @throws ParseException */
public 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 Date toDate(final String iso8601String) throws ParseException {
Calendar calendar = toCalendar(iso8601String);
return calendar.getTime();
}
}
Loading

0 comments on commit b58965b

Please sign in to comment.