You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by Benedikt Ritter <br...@apache.org> on 2015/12/17 08:23:20 UTC
Re: [lang] LANG-1192: FastDateFormat support of the week-year
component (uppercase 'Y')
-1
All Travis builds started failing after this commit [1]
Benedikt
[1] https://travis-ci.org/apache/commons-lang/builds
2015-12-14 1:39 GMT+01:00 <ch...@apache.org>:
> Repository: commons-lang
> Updated Branches:
> refs/heads/master 2ebf9a21d -> 2fa0b168d
>
>
> LANG-1192: FastDateFormat support of the week-year component (uppercase
> 'Y')
>
>
> Project: http://git-wip-us.apache.org/repos/asf/commons-lang/repo
> Commit:
> http://git-wip-us.apache.org/repos/asf/commons-lang/commit/2fa0b168
> Tree: http://git-wip-us.apache.org/repos/asf/commons-lang/tree/2fa0b168
> Diff: http://git-wip-us.apache.org/repos/asf/commons-lang/diff/2fa0b168
>
> Branch: refs/heads/master
> Commit: 2fa0b168d62a07365b2787d0ed97fa1c2cfb673b
> Parents: 2ebf9a2
> Author: Chas Honton <ch...@apache.org>
> Authored: Sun Dec 13 16:38:35 2015 -0800
> Committer: Chas Honton <ch...@apache.org>
> Committed: Sun Dec 13 16:38:35 2015 -0800
>
> ----------------------------------------------------------------------
> src/changes/changes.xml | 1 +
> .../commons/lang3/time/CalendarReflection.java | 99 ++++++++++++++++++++
> .../apache/commons/lang3/time/DateParser.java | 16 ++++
> .../commons/lang3/time/FastDateFormat.java | 11 ++-
> .../commons/lang3/time/FastDateParser.java | 32 ++++---
> .../commons/lang3/time/FastDatePrinter.java | 54 ++++++++---
> .../apache/commons/lang3/time/WeekYearTest.java | 90 ++++++++++++++++++
> 7 files changed, 276 insertions(+), 27 deletions(-)
> ----------------------------------------------------------------------
>
>
>
> http://git-wip-us.apache.org/repos/asf/commons-lang/blob/2fa0b168/src/changes/changes.xml
> ----------------------------------------------------------------------
> diff --git a/src/changes/changes.xml b/src/changes/changes.xml
> index d4904c4..7a184df 100644
> --- a/src/changes/changes.xml
> +++ b/src/changes/changes.xml
> @@ -22,6 +22,7 @@
> <body>
>
> <release version="3.5" date="tba" description="tba">
> + <action issue="LANG-1192" type="add" dev="chas" due-to="Dominik
> Stadler">FastDateFormat support of the week-year component (uppercase
> 'Y')</action>
> <action issue="LANG-1193" type="fix" dev="sebb" due-to="Qin
> Li">ordinalIndexOf("abc", "ab", 1) gives incorrect answer of -1 (correct
> answer should be 0); revert fix for LANG-1077</action>
> <action issue="LANG-1182" type="update" dev="britter" due-to="Larry
> West, Pascal Schumacher">Clarify JavaDoc of
> StringUtils.containsAny()</action>
> <action issue="LANG-1169" type="add" dev="lguibert" due-to="Rafal
> Glowinski, Robert Parr, Arman Sharif">Add StringUtils methods to compare a
> string to multiple strings</action>
>
>
> http://git-wip-us.apache.org/repos/asf/commons-lang/blob/2fa0b168/src/main/java/org/apache/commons/lang3/time/CalendarReflection.java
> ----------------------------------------------------------------------
> diff --git
> a/src/main/java/org/apache/commons/lang3/time/CalendarReflection.java
> b/src/main/java/org/apache/commons/lang3/time/CalendarReflection.java
> new file mode 100644
> index 0000000..79ebb3f
> --- /dev/null
> +++ b/src/main/java/org/apache/commons/lang3/time/CalendarReflection.java
> @@ -0,0 +1,99 @@
> +/*
> + * Licensed to the Apache Software Foundation (ASF) under one or more
> + * contributor license agreements. See the NOTICE file distributed with
> + * this work for additional information regarding copyright ownership.
> + * The ASF licenses this file to You 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 org.apache.commons.lang3.time;
> +
> +import java.lang.reflect.Method;
> +import java.util.Calendar;
> +import java.util.GregorianCalendar;
> +
> +import org.apache.commons.lang3.exception.ExceptionUtils;
> +
> +/**
> + * Use reflection to access java 1.7 methods in Calendar. This allows
> compilation with 1.6 compiler.
> + */
> +class CalendarReflection {
> +
> + private static final Method IS_WEEK_DATE_SUPPORTED =
> getCalendarMethod("isWeekDateSupported");
> + private static final Method GET_WEEK_YEAR =
> getCalendarMethod("getWeekYear");
> +
> + private static Method getCalendarMethod(String methodName,
> Class<?>... argTypes) {
> + try {
> + Method m = Calendar.class.getMethod(methodName, argTypes);
> + return m;
> + } catch (Exception e) {
> + return null;
> + }
> + }
> +
> + /**
> + * Does this calendar instance support week date?
> + * @param calendar The calendar instance.
> + * @return false, if runtime is less than java 1.7; otherwise, the
> result of calendar.isWeekDateSupported().
> + */
> + static boolean isWeekDateSupported(Calendar calendar) {
> + try {
> + return IS_WEEK_DATE_SUPPORTED!=null &&
> ((Boolean)IS_WEEK_DATE_SUPPORTED.invoke(calendar)).booleanValue();
> + } catch (Exception e) {
> + return ExceptionUtils.<Boolean>rethrow(e);
> + }
> + }
> +
> + /**
> + * Invoke getWeekYear() method of calendar instance.
> + * <p>
> + * If runtime is 1.7 or better and calendar instance support week
> year,
> + * return the value from invocation of getWeekYear().
> + * <p>
> + * If runtime is less than 1.7, and calendar is an instance of
> + * GregorianCalendar, return an approximation of the week year.
> + * (Approximation is good for all years after the Julian to Gregorian
> + * cutover.)
> + * <p>
> + * Otherwise, return the calendar instance year value.
> + *
> + * @param calendar The calendar instance.
> + * @return the week year or year value.
> + */
> + public static int getWeekYear(Calendar calendar) {
> + try {
> + if (isWeekDateSupported(calendar)) {
> + return (Integer) GET_WEEK_YEAR.invoke(calendar);
> + }
> + } catch (Exception e) {
> + return ExceptionUtils.<Integer> rethrow(e);
> + }
> +
> + int year = calendar.get(Calendar.YEAR);
> + if (IS_WEEK_DATE_SUPPORTED == null && calendar instanceof
> GregorianCalendar) {
> + // not perfect, won't work before gregorian cutover
> + // good enough for most business use.
> + switch (calendar.get(Calendar.MONTH)) {
> + case Calendar.JANUARY:
> + if (calendar.get(Calendar.WEEK_OF_YEAR) >= 52) {
> + --year;
> + }
> + break;
> + case Calendar.DECEMBER:
> + if (calendar.get(Calendar.WEEK_OF_YEAR) == 1) {
> + ++year;
> + }
> + break;
> + }
> + }
> + return year;
> + }
> +}
>
>
> http://git-wip-us.apache.org/repos/asf/commons-lang/blob/2fa0b168/src/main/java/org/apache/commons/lang3/time/DateParser.java
> ----------------------------------------------------------------------
> diff --git a/src/main/java/org/apache/commons/lang3/time/DateParser.java
> b/src/main/java/org/apache/commons/lang3/time/DateParser.java
> index 120c4ab..c91f9a2 100644
> --- a/src/main/java/org/apache/commons/lang3/time/DateParser.java
> +++ b/src/main/java/org/apache/commons/lang3/time/DateParser.java
> @@ -18,6 +18,7 @@ package org.apache.commons.lang3.time;
>
> import java.text.ParseException;
> import java.text.ParsePosition;
> +import java.util.Calendar;
> import java.util.Date;
> import java.util.Locale;
> import java.util.TimeZone;
> @@ -53,6 +54,21 @@ public interface DateParser {
> */
> Date parse(String source, ParsePosition pos);
>
> + /**
> + * Parse a formatted date string according to the format. Updates
> the Calendar with parsed fields.
> + * Upon success, the ParsePosition index is updated to indicate how
> much of the source text was consumed.
> + * Not all source text needs to be consumed. Upon parse failure,
> ParsePosition error index is updated to
> + * the offset of the source text which does not match the supplied
> format.
> + *
> + * @param source The text to parse.
> + * @param pos On input, the position in the source to start parsing,
> on output, updated position.
> + * @param calendar The calendar into which to set parsed fields.
> + * @return true, if source has been parsed (pos parsePosition is
> updated); otherwise false (and pos errorIndex is updated)
> + * @throws IllegalArgumentException when Calendar has been set to be
> not lenient, and a parsed field is
> + * out of range.
> + */
> + boolean parse(String source, ParsePosition pos, Calendar calendar);
> +
> // Accessors
>
> //-----------------------------------------------------------------------
> /**
>
>
> http://git-wip-us.apache.org/repos/asf/commons-lang/blob/2fa0b168/src/main/java/org/apache/commons/lang3/time/FastDateFormat.java
> ----------------------------------------------------------------------
> diff --git
> a/src/main/java/org/apache/commons/lang3/time/FastDateFormat.java
> b/src/main/java/org/apache/commons/lang3/time/FastDateFormat.java
> index abb5198..c2907b2 100644
> --- a/src/main/java/org/apache/commons/lang3/time/FastDateFormat.java
> +++ b/src/main/java/org/apache/commons/lang3/time/FastDateFormat.java
> @@ -550,7 +550,16 @@ public class FastDateFormat extends Format implements
> DateParser, DatePrinter {
> */
> @Override
> public Date parse(final String source, final ParsePosition pos) {
> - return parser.parse(source, pos);
> + return parser.parse(source, pos);
> + }
> +
> + /*
> + * (non-Javadoc)
> + * @see
> org.apache.commons.lang3.time.DateParser#parse(java.lang.String,
> java.text.ParsePosition, java.util.Calendar)
> + */
> + @Override
> + public boolean parse(final String source, final ParsePosition pos,
> final Calendar calendar) {
> + return parser.parse(source, pos, calendar);
> }
>
> /* (non-Javadoc)
>
>
> http://git-wip-us.apache.org/repos/asf/commons-lang/blob/2fa0b168/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
> ----------------------------------------------------------------------
> diff --git
> a/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
> b/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
> index 4dc897b..8210ee3 100644
> --- a/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
> +++ b/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
> @@ -170,7 +170,7 @@ public class FastDateParser implements DateParser,
> Serializable {
>
> //-----------------------------------------------------------------------
>
> /**
> - * Struct to hold strategy and filed width
> + * Struct to hold strategy and field width
> */
> private static class StrategyAndWidth {
> final Strategy strategy;
> @@ -401,12 +401,12 @@ public class FastDateParser implements DateParser,
> Serializable {
>
> return parse(source, pos, cal) ?cal.getTime() :null;
> }
> -
> +
> /**
> - * Parse a formatted date string according to the format. Updates
> the Calendar with parsed fields.
> + * Parse a formatted date string according to the format. Updates
> the Calendar with parsed fields.
> * Upon success, the ParsePosition index is updated to indicate how
> much of the source text was consumed.
> * Not all source text needs to be consumed. Upon parse failure,
> ParsePosition error index is updated to
> - * the offset of the source text which does not match the supplied
> format.
> + * the offset of the source text which does not match the supplied
> format.
> *
> * @param source The text to parse.
> * @param pos On input, the position in the source to start parsing,
> on output, updated position.
> @@ -415,17 +415,18 @@ public class FastDateParser implements DateParser,
> Serializable {
> * @throws IllegalArgumentException when Calendar has been set to be
> not lenient, and a parsed field is
> * out of range.
> */
> - public boolean parse(final String source, final ParsePosition pos,
> final Calendar calendar) {
> - ListIterator<StrategyAndWidth> lt = patterns.listIterator();
> - while(lt.hasNext()) {
> - StrategyAndWidth pattern = lt.next();
> - int maxWidth = pattern.getMaxWidth(lt);
> - if(!pattern.strategy.parse(this, calendar, source, pos,
> maxWidth)) {
> - return false;
> - }
> - }
> - return true;
> - }
> + @Override
> + public boolean parse(final String source, final ParsePosition pos,
> final Calendar calendar) {
> + ListIterator<StrategyAndWidth> lt = patterns.listIterator();
> + while(lt.hasNext()) {
> + StrategyAndWidth pattern = lt.next();
> + int maxWidth = pattern.getMaxWidth(lt);
> + if(!pattern.strategy.parse(this, calendar, source, pos,
> maxWidth)) {
> + return false;
> + }
> + }
> + return true;
> + }
>
> // Support for strategies
>
> //-----------------------------------------------------------------------
> @@ -606,6 +607,7 @@ public class FastDateParser implements DateParser,
> Serializable {
> case 'w':
> return WEEK_OF_YEAR_STRATEGY;
> case 'y':
> + case 'Y':
> return width>2 ?LITERAL_YEAR_STRATEGY
> :ABBREVIATED_YEAR_STRATEGY;
> case 'X':
> return ISO8601TimeZoneStrategy.getStrategy(width);
>
>
> http://git-wip-us.apache.org/repos/asf/commons-lang/blob/2fa0b168/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
> ----------------------------------------------------------------------
> diff --git
> a/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
> b/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
> index 4f84cc7..f044552 100644
> --- a/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
> +++ b/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
> @@ -25,7 +25,6 @@ import java.text.FieldPosition;
> import java.util.ArrayList;
> import java.util.Calendar;
> import java.util.Date;
> -import java.util.GregorianCalendar;
> import java.util.List;
> import java.util.Locale;
> import java.util.TimeZone;
> @@ -211,11 +210,15 @@ public class FastDatePrinter implements DatePrinter,
> Serializable {
> rule = new TextField(Calendar.ERA, ERAs);
> break;
> case 'y': // year (number)
> + case 'Y': // week year
> if (tokenLen == 2) {
> rule = TwoDigitYearField.INSTANCE;
> } else {
> rule = selectNumberRule(Calendar.YEAR, tokenLen < 4 ?
> 4 : tokenLen);
> }
> + if (c == 'Y') {
> + rule = new WeekYear((NumberRule) rule);
> + }
> break;
> case 'M': // month in year (text and number)
> if (tokenLen >= 4) {
> @@ -438,7 +441,7 @@ public class FastDatePrinter implements DatePrinter,
> Serializable {
> */
> @Override
> public String format(final long millis) {
> - final Calendar c = newCalendar(); // hard code GregorianCalendar
> + final Calendar c = newCalendar();
> c.setTimeInMillis(millis);
> return applyRulesToString(c);
> }
> @@ -453,12 +456,11 @@ public class FastDatePrinter implements DatePrinter,
> Serializable {
> }
>
> /**
> - * Creation method for ne calender instances.
> + * Creation method for new calender instances.
> * @return a new Calendar instance.
> */
> - private GregorianCalendar newCalendar() {
> - // hard code GregorianCalendar
> - return new GregorianCalendar(mTimeZone, mLocale);
> + private Calendar newCalendar() {
> + return Calendar.getInstance(mTimeZone, mLocale);
> }
>
> /* (non-Javadoc)
> @@ -466,7 +468,7 @@ public class FastDatePrinter implements DatePrinter,
> Serializable {
> */
> @Override
> public String format(final Date date) {
> - final Calendar c = newCalendar(); // hard code GregorianCalendar
> + final Calendar c = newCalendar();
> c.setTime(date);
> return applyRulesToString(c);
> }
> @@ -492,7 +494,7 @@ public class FastDatePrinter implements DatePrinter,
> Serializable {
> */
> @Override
> public StringBuffer format(final Date date, final StringBuffer buf) {
> - final Calendar c = newCalendar(); // hard code GregorianCalendar
> + final Calendar c = newCalendar();
> c.setTime(date);
> return applyRules(c, buf);
> }
> @@ -519,7 +521,7 @@ public class FastDatePrinter implements DatePrinter,
> Serializable {
> */
> @Override
> public <B extends Appendable> B format(final Date date, final B buf) {
> - final Calendar c = newCalendar(); // hard code GregorianCalendar
> + final Calendar c = newCalendar();
> c.setTime(date);
> return applyRules(c, buf);
> }
> @@ -528,9 +530,13 @@ public class FastDatePrinter implements DatePrinter,
> Serializable {
> * @see
> org.apache.commons.lang3.time.DatePrinter#format(java.util.Calendar,
> java.lang.Appendable)
> */
> @Override
> - public <B extends Appendable> B format(final Calendar calendar, final
> B buf) {
> + public <B extends Appendable> B format(Calendar calendar, final B
> buf) {
> // do not pass in calendar directly, this will cause TimeZone of
> FastDatePrinter to be ignored
> - return format(calendar.getTime(), buf);
> + if(!calendar.getTimeZone().equals(mTimeZone)) {
> + calendar = (Calendar)calendar.clone();
> + calendar.setTimeZone(mTimeZone);
> + }
> + return applyRules(calendar, buf);
> }
>
> /**
> @@ -1202,6 +1208,32 @@ public class FastDatePrinter implements
> DatePrinter, Serializable {
> }
> }
>
> + /**
> + * <p>Inner class to output the numeric day in week.</p>
> + */
> + private static class WeekYear implements NumberRule {
> + private final NumberRule mRule;
> +
> + WeekYear(final NumberRule rule) {
> + mRule = rule;
> + }
> +
> + @Override
> + public int estimateLength() {
> + return mRule.estimateLength();
> + }
> +
> + @Override
> + public void appendTo(final Appendable buffer, final Calendar
> calendar) throws IOException {
> + mRule.appendTo(buffer,
> CalendarReflection.getWeekYear(calendar));
> + }
> +
> + @Override
> + public void appendTo(final Appendable buffer, final int value)
> throws IOException {
> + mRule.appendTo(buffer, value);
> + }
> + }
> +
>
> //-----------------------------------------------------------------------
>
> private static final ConcurrentMap<TimeZoneDisplayKey, String>
> cTimeZoneDisplayCache =
>
>
> http://git-wip-us.apache.org/repos/asf/commons-lang/blob/2fa0b168/src/test/java/org/apache/commons/lang3/time/WeekYearTest.java
> ----------------------------------------------------------------------
> diff --git a/src/test/java/org/apache/commons/lang3/time/WeekYearTest.java
> b/src/test/java/org/apache/commons/lang3/time/WeekYearTest.java
> new file mode 100644
> index 0000000..95f5ad8
> --- /dev/null
> +++ b/src/test/java/org/apache/commons/lang3/time/WeekYearTest.java
> @@ -0,0 +1,90 @@
> +/*
> + * Licensed to the Apache Software Foundation (ASF) under one or more
> + * contributor license agreements. See the NOTICE file distributed with
> + * this work for additional information regarding copyright ownership.
> + * The ASF licenses this file to You 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 org.apache.commons.lang3.time;
> +
> +import java.text.ParseException;
> +import java.text.ParsePosition;
> +import java.util.Arrays;
> +import java.util.Calendar;
> +import java.util.Collection;
> +import java.util.GregorianCalendar;
> +import java.util.Locale;
> +import java.util.TimeZone;
> +
> +import org.junit.Assert;
> +import org.junit.Test;
> +import org.junit.runner.RunWith;
> +import org.junit.runners.Parameterized;
> +import org.junit.runners.Parameterized.Parameters;
> +
> +@RunWith(Parameterized.class)
> +public class WeekYearTest {
> +
> + @Parameters(name = "{index}: {3}")
> + public static Collection<Object[]> data() {
> + return Arrays
> + .asList(new Object[][] {
> + { 2005, Calendar.JANUARY, 1, "2004-W53-6" },
> + { 2005, Calendar.JANUARY, 2, "2004-W53-7" },
> + { 2005, Calendar.DECEMBER, 31, "2005-W52-6" },
> + { 2007, Calendar.JANUARY, 1, "2007-W01-1" },
> + { 2007, Calendar.DECEMBER, 30, "2007-W52-7" },
> + { 2007, Calendar.DECEMBER, 31, "2008-W01-1" },
> + { 2008, Calendar.JANUARY, 1, "2008-W01-2" },
> + { 2008, Calendar.DECEMBER, 28, "2008-W52-7" },
> + { 2008, Calendar.DECEMBER, 29, "2009-W01-1" },
> + { 2008, Calendar.DECEMBER, 30, "2009-W01-2" },
> + { 2008, Calendar.DECEMBER, 31, "2009-W01-3" },
> + { 2009, Calendar.JANUARY, 1, "2009-W01-4" },
> + { 2009, Calendar.DECEMBER, 31, "2009-W53-4" },
> + { 2010, Calendar.JANUARY, 1, "2009-W53-5" },
> + { 2010, Calendar.JANUARY, 2, "2009-W53-6" },
> + { 2010, Calendar.JANUARY, 3, "2009-W53-7" }
> + });
> + }
> +
> + final Calendar vulgar;
> + final String isoForm;
> +
> + public WeekYearTest(int year, int month, int day, String isoForm) {
> + vulgar = new GregorianCalendar(year, month, day);
> + this.isoForm = isoForm;
> + }
> +
> + @Test
> + public void testParser() throws ParseException {
> + final DateParser parser = new FastDateParser("YYYY-'W'ww-u",
> TimeZone.getDefault(), Locale.getDefault());
> +
> + Calendar cal = Calendar.getInstance();
> + cal.setMinimalDaysInFirstWeek(4);
> + cal.setFirstDayOfWeek(Calendar.MONDAY);
> + cal.clear();
> +
> + parser.parse(isoForm, new ParsePosition(0), cal);
> + Assert.assertEquals(vulgar.getTime(), cal.getTime());
> + }
> +
> + @Test
> + public void testPrinter() {
> + final FastDatePrinter printer = new
> FastDatePrinter("YYYY-'W'ww-u", TimeZone.getDefault(), Locale.getDefault());
> +
> + vulgar.setMinimalDaysInFirstWeek(4);
> + vulgar.setFirstDayOfWeek(Calendar.MONDAY);
> +
> + Assert.assertEquals(isoForm, printer.format(vulgar));
> + }
> +}
>
>
--
http://home.apache.org/~britter/
http://twitter.com/BenediktRitter
http://github.com/britter
Re: [lang] LANG-1192: FastDateFormat support of the week-year
component (uppercase 'Y')
Posted by ch...@honton.org.
Reverted pending investigation of travis failures
chas
Quoting Benedikt Ritter <br...@apache.org>:
> -1
>
> All Travis builds started failing after this commit [1]
>
> Benedikt
>
> [1] https://travis-ci.org/apache/commons-lang/builds
>
> 2015-12-14 1:39 GMT+01:00 <ch...@apache.org>:
>
>> Repository: commons-lang
>> Updated Branches:
>> refs/heads/master 2ebf9a21d -> 2fa0b168d
>>
>>
>> LANG-1192: FastDateFormat support of the week-year component (uppercase
>> 'Y')
>>
>>
>> Project: http://git-wip-us.apache.org/repos/asf/commons-lang/repo
>> Commit:
>> http://git-wip-us.apache.org/repos/asf/commons-lang/commit/2fa0b168
>> Tree: http://git-wip-us.apache.org/repos/asf/commons-lang/tree/2fa0b168
>> Diff: http://git-wip-us.apache.org/repos/asf/commons-lang/diff/2fa0b168
>>
>> Branch: refs/heads/master
>> Commit: 2fa0b168d62a07365b2787d0ed97fa1c2cfb673b
>> Parents: 2ebf9a2
>> Author: Chas Honton <ch...@apache.org>
>> Authored: Sun Dec 13 16:38:35 2015 -0800
>> Committer: Chas Honton <ch...@apache.org>
>> Committed: Sun Dec 13 16:38:35 2015 -0800
>>
>> ----------------------------------------------------------------------
>> src/changes/changes.xml | 1 +
>> .../commons/lang3/time/CalendarReflection.java | 99 ++++++++++++++++++++
>> .../apache/commons/lang3/time/DateParser.java | 16 ++++
>> .../commons/lang3/time/FastDateFormat.java | 11 ++-
>> .../commons/lang3/time/FastDateParser.java | 32 ++++---
>> .../commons/lang3/time/FastDatePrinter.java | 54 ++++++++---
>> .../apache/commons/lang3/time/WeekYearTest.java | 90 ++++++++++++++++++
>> 7 files changed, 276 insertions(+), 27 deletions(-)
>> ----------------------------------------------------------------------
>>
>>
>>
>> http://git-wip-us.apache.org/repos/asf/commons-lang/blob/2fa0b168/src/changes/changes.xml
>> ----------------------------------------------------------------------
>> diff --git a/src/changes/changes.xml b/src/changes/changes.xml
>> index d4904c4..7a184df 100644
>> --- a/src/changes/changes.xml
>> +++ b/src/changes/changes.xml
>> @@ -22,6 +22,7 @@
>> <body>
>>
>> <release version="3.5" date="tba" description="tba">
>> + <action issue="LANG-1192" type="add" dev="chas" due-to="Dominik
>> Stadler">FastDateFormat support of the week-year component (uppercase
>> 'Y')</action>
>> <action issue="LANG-1193" type="fix" dev="sebb" due-to="Qin
>> Li">ordinalIndexOf("abc", "ab", 1) gives incorrect answer of -1 (correct
>> answer should be 0); revert fix for LANG-1077</action>
>> <action issue="LANG-1182" type="update" dev="britter" due-to="Larry
>> West, Pascal Schumacher">Clarify JavaDoc of
>> StringUtils.containsAny()</action>
>> <action issue="LANG-1169" type="add" dev="lguibert" due-to="Rafal
>> Glowinski, Robert Parr, Arman Sharif">Add StringUtils methods to compare a
>> string to multiple strings</action>
>>
>>
>> http://git-wip-us.apache.org/repos/asf/commons-lang/blob/2fa0b168/src/main/java/org/apache/commons/lang3/time/CalendarReflection.java
>> ----------------------------------------------------------------------
>> diff --git
>> a/src/main/java/org/apache/commons/lang3/time/CalendarReflection.java
>> b/src/main/java/org/apache/commons/lang3/time/CalendarReflection.java
>> new file mode 100644
>> index 0000000..79ebb3f
>> --- /dev/null
>> +++ b/src/main/java/org/apache/commons/lang3/time/CalendarReflection.java
>> @@ -0,0 +1,99 @@
>> +/*
>> + * Licensed to the Apache Software Foundation (ASF) under one or more
>> + * contributor license agreements. See the NOTICE file distributed with
>> + * this work for additional information regarding copyright ownership.
>> + * The ASF licenses this file to You 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 org.apache.commons.lang3.time;
>> +
>> +import java.lang.reflect.Method;
>> +import java.util.Calendar;
>> +import java.util.GregorianCalendar;
>> +
>> +import org.apache.commons.lang3.exception.ExceptionUtils;
>> +
>> +/**
>> + * Use reflection to access java 1.7 methods in Calendar. This allows
>> compilation with 1.6 compiler.
>> + */
>> +class CalendarReflection {
>> +
>> + private static final Method IS_WEEK_DATE_SUPPORTED =
>> getCalendarMethod("isWeekDateSupported");
>> + private static final Method GET_WEEK_YEAR =
>> getCalendarMethod("getWeekYear");
>> +
>> + private static Method getCalendarMethod(String methodName,
>> Class<?>... argTypes) {
>> + try {
>> + Method m = Calendar.class.getMethod(methodName, argTypes);
>> + return m;
>> + } catch (Exception e) {
>> + return null;
>> + }
>> + }
>> +
>> + /**
>> + * Does this calendar instance support week date?
>> + * @param calendar The calendar instance.
>> + * @return false, if runtime is less than java 1.7; otherwise, the
>> result of calendar.isWeekDateSupported().
>> + */
>> + static boolean isWeekDateSupported(Calendar calendar) {
>> + try {
>> + return IS_WEEK_DATE_SUPPORTED!=null &&
>> ((Boolean)IS_WEEK_DATE_SUPPORTED.invoke(calendar)).booleanValue();
>> + } catch (Exception e) {
>> + return ExceptionUtils.<Boolean>rethrow(e);
>> + }
>> + }
>> +
>> + /**
>> + * Invoke getWeekYear() method of calendar instance.
>> + * <p>
>> + * If runtime is 1.7 or better and calendar instance support week
>> year,
>> + * return the value from invocation of getWeekYear().
>> + * <p>
>> + * If runtime is less than 1.7, and calendar is an instance of
>> + * GregorianCalendar, return an approximation of the week year.
>> + * (Approximation is good for all years after the Julian to Gregorian
>> + * cutover.)
>> + * <p>
>> + * Otherwise, return the calendar instance year value.
>> + *
>> + * @param calendar The calendar instance.
>> + * @return the week year or year value.
>> + */
>> + public static int getWeekYear(Calendar calendar) {
>> + try {
>> + if (isWeekDateSupported(calendar)) {
>> + return (Integer) GET_WEEK_YEAR.invoke(calendar);
>> + }
>> + } catch (Exception e) {
>> + return ExceptionUtils.<Integer> rethrow(e);
>> + }
>> +
>> + int year = calendar.get(Calendar.YEAR);
>> + if (IS_WEEK_DATE_SUPPORTED == null && calendar instanceof
>> GregorianCalendar) {
>> + // not perfect, won't work before gregorian cutover
>> + // good enough for most business use.
>> + switch (calendar.get(Calendar.MONTH)) {
>> + case Calendar.JANUARY:
>> + if (calendar.get(Calendar.WEEK_OF_YEAR) >= 52) {
>> + --year;
>> + }
>> + break;
>> + case Calendar.DECEMBER:
>> + if (calendar.get(Calendar.WEEK_OF_YEAR) == 1) {
>> + ++year;
>> + }
>> + break;
>> + }
>> + }
>> + return year;
>> + }
>> +}
>>
>>
>> http://git-wip-us.apache.org/repos/asf/commons-lang/blob/2fa0b168/src/main/java/org/apache/commons/lang3/time/DateParser.java
>> ----------------------------------------------------------------------
>> diff --git a/src/main/java/org/apache/commons/lang3/time/DateParser.java
>> b/src/main/java/org/apache/commons/lang3/time/DateParser.java
>> index 120c4ab..c91f9a2 100644
>> --- a/src/main/java/org/apache/commons/lang3/time/DateParser.java
>> +++ b/src/main/java/org/apache/commons/lang3/time/DateParser.java
>> @@ -18,6 +18,7 @@ package org.apache.commons.lang3.time;
>>
>> import java.text.ParseException;
>> import java.text.ParsePosition;
>> +import java.util.Calendar;
>> import java.util.Date;
>> import java.util.Locale;
>> import java.util.TimeZone;
>> @@ -53,6 +54,21 @@ public interface DateParser {
>> */
>> Date parse(String source, ParsePosition pos);
>>
>> + /**
>> + * Parse a formatted date string according to the format. Updates
>> the Calendar with parsed fields.
>> + * Upon success, the ParsePosition index is updated to indicate how
>> much of the source text was consumed.
>> + * Not all source text needs to be consumed. Upon parse failure,
>> ParsePosition error index is updated to
>> + * the offset of the source text which does not match the supplied
>> format.
>> + *
>> + * @param source The text to parse.
>> + * @param pos On input, the position in the source to start parsing,
>> on output, updated position.
>> + * @param calendar The calendar into which to set parsed fields.
>> + * @return true, if source has been parsed (pos parsePosition is
>> updated); otherwise false (and pos errorIndex is updated)
>> + * @throws IllegalArgumentException when Calendar has been set to be
>> not lenient, and a parsed field is
>> + * out of range.
>> + */
>> + boolean parse(String source, ParsePosition pos, Calendar calendar);
>> +
>> // Accessors
>>
>> //-----------------------------------------------------------------------
>> /**
>>
>>
>> http://git-wip-us.apache.org/repos/asf/commons-lang/blob/2fa0b168/src/main/java/org/apache/commons/lang3/time/FastDateFormat.java
>> ----------------------------------------------------------------------
>> diff --git
>> a/src/main/java/org/apache/commons/lang3/time/FastDateFormat.java
>> b/src/main/java/org/apache/commons/lang3/time/FastDateFormat.java
>> index abb5198..c2907b2 100644
>> --- a/src/main/java/org/apache/commons/lang3/time/FastDateFormat.java
>> +++ b/src/main/java/org/apache/commons/lang3/time/FastDateFormat.java
>> @@ -550,7 +550,16 @@ public class FastDateFormat extends Format implements
>> DateParser, DatePrinter {
>> */
>> @Override
>> public Date parse(final String source, final ParsePosition pos) {
>> - return parser.parse(source, pos);
>> + return parser.parse(source, pos);
>> + }
>> +
>> + /*
>> + * (non-Javadoc)
>> + * @see
>> org.apache.commons.lang3.time.DateParser#parse(java.lang.String,
>> java.text.ParsePosition, java.util.Calendar)
>> + */
>> + @Override
>> + public boolean parse(final String source, final ParsePosition pos,
>> final Calendar calendar) {
>> + return parser.parse(source, pos, calendar);
>> }
>>
>> /* (non-Javadoc)
>>
>>
>> http://git-wip-us.apache.org/repos/asf/commons-lang/blob/2fa0b168/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
>> ----------------------------------------------------------------------
>> diff --git
>> a/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
>> b/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
>> index 4dc897b..8210ee3 100644
>> --- a/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
>> +++ b/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
>> @@ -170,7 +170,7 @@ public class FastDateParser implements DateParser,
>> Serializable {
>>
>> //-----------------------------------------------------------------------
>>
>> /**
>> - * Struct to hold strategy and filed width
>> + * Struct to hold strategy and field width
>> */
>> private static class StrategyAndWidth {
>> final Strategy strategy;
>> @@ -401,12 +401,12 @@ public class FastDateParser implements DateParser,
>> Serializable {
>>
>> return parse(source, pos, cal) ?cal.getTime() :null;
>> }
>> -
>> +
>> /**
>> - * Parse a formatted date string according to the format. Updates
>> the Calendar with parsed fields.
>> + * Parse a formatted date string according to the format. Updates
>> the Calendar with parsed fields.
>> * Upon success, the ParsePosition index is updated to indicate how
>> much of the source text was consumed.
>> * Not all source text needs to be consumed. Upon parse failure,
>> ParsePosition error index is updated to
>> - * the offset of the source text which does not match the supplied
>> format.
>> + * the offset of the source text which does not match the supplied
>> format.
>> *
>> * @param source The text to parse.
>> * @param pos On input, the position in the source to start parsing,
>> on output, updated position.
>> @@ -415,17 +415,18 @@ public class FastDateParser implements DateParser,
>> Serializable {
>> * @throws IllegalArgumentException when Calendar has been set to be
>> not lenient, and a parsed field is
>> * out of range.
>> */
>> - public boolean parse(final String source, final ParsePosition pos,
>> final Calendar calendar) {
>> - ListIterator<StrategyAndWidth> lt = patterns.listIterator();
>> - while(lt.hasNext()) {
>> - StrategyAndWidth pattern = lt.next();
>> - int maxWidth = pattern.getMaxWidth(lt);
>> - if(!pattern.strategy.parse(this, calendar, source, pos,
>> maxWidth)) {
>> - return false;
>> - }
>> - }
>> - return true;
>> - }
>> + @Override
>> + public boolean parse(final String source, final ParsePosition pos,
>> final Calendar calendar) {
>> + ListIterator<StrategyAndWidth> lt = patterns.listIterator();
>> + while(lt.hasNext()) {
>> + StrategyAndWidth pattern = lt.next();
>> + int maxWidth = pattern.getMaxWidth(lt);
>> + if(!pattern.strategy.parse(this, calendar, source, pos,
>> maxWidth)) {
>> + return false;
>> + }
>> + }
>> + return true;
>> + }
>>
>> // Support for strategies
>>
>> //-----------------------------------------------------------------------
>> @@ -606,6 +607,7 @@ public class FastDateParser implements DateParser,
>> Serializable {
>> case 'w':
>> return WEEK_OF_YEAR_STRATEGY;
>> case 'y':
>> + case 'Y':
>> return width>2 ?LITERAL_YEAR_STRATEGY
>> :ABBREVIATED_YEAR_STRATEGY;
>> case 'X':
>> return ISO8601TimeZoneStrategy.getStrategy(width);
>>
>>
>> http://git-wip-us.apache.org/repos/asf/commons-lang/blob/2fa0b168/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
>> ----------------------------------------------------------------------
>> diff --git
>> a/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
>> b/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
>> index 4f84cc7..f044552 100644
>> --- a/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
>> +++ b/src/main/java/org/apache/commons/lang3/time/FastDatePrinter.java
>> @@ -25,7 +25,6 @@ import java.text.FieldPosition;
>> import java.util.ArrayList;
>> import java.util.Calendar;
>> import java.util.Date;
>> -import java.util.GregorianCalendar;
>> import java.util.List;
>> import java.util.Locale;
>> import java.util.TimeZone;
>> @@ -211,11 +210,15 @@ public class FastDatePrinter implements DatePrinter,
>> Serializable {
>> rule = new TextField(Calendar.ERA, ERAs);
>> break;
>> case 'y': // year (number)
>> + case 'Y': // week year
>> if (tokenLen == 2) {
>> rule = TwoDigitYearField.INSTANCE;
>> } else {
>> rule = selectNumberRule(Calendar.YEAR, tokenLen < 4 ?
>> 4 : tokenLen);
>> }
>> + if (c == 'Y') {
>> + rule = new WeekYear((NumberRule) rule);
>> + }
>> break;
>> case 'M': // month in year (text and number)
>> if (tokenLen >= 4) {
>> @@ -438,7 +441,7 @@ public class FastDatePrinter implements DatePrinter,
>> Serializable {
>> */
>> @Override
>> public String format(final long millis) {
>> - final Calendar c = newCalendar(); // hard code GregorianCalendar
>> + final Calendar c = newCalendar();
>> c.setTimeInMillis(millis);
>> return applyRulesToString(c);
>> }
>> @@ -453,12 +456,11 @@ public class FastDatePrinter implements DatePrinter,
>> Serializable {
>> }
>>
>> /**
>> - * Creation method for ne calender instances.
>> + * Creation method for new calender instances.
>> * @return a new Calendar instance.
>> */
>> - private GregorianCalendar newCalendar() {
>> - // hard code GregorianCalendar
>> - return new GregorianCalendar(mTimeZone, mLocale);
>> + private Calendar newCalendar() {
>> + return Calendar.getInstance(mTimeZone, mLocale);
>> }
>>
>> /* (non-Javadoc)
>> @@ -466,7 +468,7 @@ public class FastDatePrinter implements DatePrinter,
>> Serializable {
>> */
>> @Override
>> public String format(final Date date) {
>> - final Calendar c = newCalendar(); // hard code GregorianCalendar
>> + final Calendar c = newCalendar();
>> c.setTime(date);
>> return applyRulesToString(c);
>> }
>> @@ -492,7 +494,7 @@ public class FastDatePrinter implements DatePrinter,
>> Serializable {
>> */
>> @Override
>> public StringBuffer format(final Date date, final StringBuffer buf) {
>> - final Calendar c = newCalendar(); // hard code GregorianCalendar
>> + final Calendar c = newCalendar();
>> c.setTime(date);
>> return applyRules(c, buf);
>> }
>> @@ -519,7 +521,7 @@ public class FastDatePrinter implements DatePrinter,
>> Serializable {
>> */
>> @Override
>> public <B extends Appendable> B format(final Date date, final B buf) {
>> - final Calendar c = newCalendar(); // hard code GregorianCalendar
>> + final Calendar c = newCalendar();
>> c.setTime(date);
>> return applyRules(c, buf);
>> }
>> @@ -528,9 +530,13 @@ public class FastDatePrinter implements DatePrinter,
>> Serializable {
>> * @see
>> org.apache.commons.lang3.time.DatePrinter#format(java.util.Calendar,
>> java.lang.Appendable)
>> */
>> @Override
>> - public <B extends Appendable> B format(final Calendar calendar, final
>> B buf) {
>> + public <B extends Appendable> B format(Calendar calendar, final B
>> buf) {
>> // do not pass in calendar directly, this will cause TimeZone of
>> FastDatePrinter to be ignored
>> - return format(calendar.getTime(), buf);
>> + if(!calendar.getTimeZone().equals(mTimeZone)) {
>> + calendar = (Calendar)calendar.clone();
>> + calendar.setTimeZone(mTimeZone);
>> + }
>> + return applyRules(calendar, buf);
>> }
>>
>> /**
>> @@ -1202,6 +1208,32 @@ public class FastDatePrinter implements
>> DatePrinter, Serializable {
>> }
>> }
>>
>> + /**
>> + * <p>Inner class to output the numeric day in week.</p>
>> + */
>> + private static class WeekYear implements NumberRule {
>> + private final NumberRule mRule;
>> +
>> + WeekYear(final NumberRule rule) {
>> + mRule = rule;
>> + }
>> +
>> + @Override
>> + public int estimateLength() {
>> + return mRule.estimateLength();
>> + }
>> +
>> + @Override
>> + public void appendTo(final Appendable buffer, final Calendar
>> calendar) throws IOException {
>> + mRule.appendTo(buffer,
>> CalendarReflection.getWeekYear(calendar));
>> + }
>> +
>> + @Override
>> + public void appendTo(final Appendable buffer, final int value)
>> throws IOException {
>> + mRule.appendTo(buffer, value);
>> + }
>> + }
>> +
>>
>> //-----------------------------------------------------------------------
>>
>> private static final ConcurrentMap<TimeZoneDisplayKey, String>
>> cTimeZoneDisplayCache =
>>
>>
>> http://git-wip-us.apache.org/repos/asf/commons-lang/blob/2fa0b168/src/test/java/org/apache/commons/lang3/time/WeekYearTest.java
>> ----------------------------------------------------------------------
>> diff --git a/src/test/java/org/apache/commons/lang3/time/WeekYearTest.java
>> b/src/test/java/org/apache/commons/lang3/time/WeekYearTest.java
>> new file mode 100644
>> index 0000000..95f5ad8
>> --- /dev/null
>> +++ b/src/test/java/org/apache/commons/lang3/time/WeekYearTest.java
>> @@ -0,0 +1,90 @@
>> +/*
>> + * Licensed to the Apache Software Foundation (ASF) under one or more
>> + * contributor license agreements. See the NOTICE file distributed with
>> + * this work for additional information regarding copyright ownership.
>> + * The ASF licenses this file to You 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 org.apache.commons.lang3.time;
>> +
>> +import java.text.ParseException;
>> +import java.text.ParsePosition;
>> +import java.util.Arrays;
>> +import java.util.Calendar;
>> +import java.util.Collection;
>> +import java.util.GregorianCalendar;
>> +import java.util.Locale;
>> +import java.util.TimeZone;
>> +
>> +import org.junit.Assert;
>> +import org.junit.Test;
>> +import org.junit.runner.RunWith;
>> +import org.junit.runners.Parameterized;
>> +import org.junit.runners.Parameterized.Parameters;
>> +
>> +@RunWith(Parameterized.class)
>> +public class WeekYearTest {
>> +
>> + @Parameters(name = "{index}: {3}")
>> + public static Collection<Object[]> data() {
>> + return Arrays
>> + .asList(new Object[][] {
>> + { 2005, Calendar.JANUARY, 1, "2004-W53-6" },
>> + { 2005, Calendar.JANUARY, 2, "2004-W53-7" },
>> + { 2005, Calendar.DECEMBER, 31, "2005-W52-6" },
>> + { 2007, Calendar.JANUARY, 1, "2007-W01-1" },
>> + { 2007, Calendar.DECEMBER, 30, "2007-W52-7" },
>> + { 2007, Calendar.DECEMBER, 31, "2008-W01-1" },
>> + { 2008, Calendar.JANUARY, 1, "2008-W01-2" },
>> + { 2008, Calendar.DECEMBER, 28, "2008-W52-7" },
>> + { 2008, Calendar.DECEMBER, 29, "2009-W01-1" },
>> + { 2008, Calendar.DECEMBER, 30, "2009-W01-2" },
>> + { 2008, Calendar.DECEMBER, 31, "2009-W01-3" },
>> + { 2009, Calendar.JANUARY, 1, "2009-W01-4" },
>> + { 2009, Calendar.DECEMBER, 31, "2009-W53-4" },
>> + { 2010, Calendar.JANUARY, 1, "2009-W53-5" },
>> + { 2010, Calendar.JANUARY, 2, "2009-W53-6" },
>> + { 2010, Calendar.JANUARY, 3, "2009-W53-7" }
>> + });
>> + }
>> +
>> + final Calendar vulgar;
>> + final String isoForm;
>> +
>> + public WeekYearTest(int year, int month, int day, String isoForm) {
>> + vulgar = new GregorianCalendar(year, month, day);
>> + this.isoForm = isoForm;
>> + }
>> +
>> + @Test
>> + public void testParser() throws ParseException {
>> + final DateParser parser = new FastDateParser("YYYY-'W'ww-u",
>> TimeZone.getDefault(), Locale.getDefault());
>> +
>> + Calendar cal = Calendar.getInstance();
>> + cal.setMinimalDaysInFirstWeek(4);
>> + cal.setFirstDayOfWeek(Calendar.MONDAY);
>> + cal.clear();
>> +
>> + parser.parse(isoForm, new ParsePosition(0), cal);
>> + Assert.assertEquals(vulgar.getTime(), cal.getTime());
>> + }
>> +
>> + @Test
>> + public void testPrinter() {
>> + final FastDatePrinter printer = new
>> FastDatePrinter("YYYY-'W'ww-u", TimeZone.getDefault(), Locale.getDefault());
>> +
>> + vulgar.setMinimalDaysInFirstWeek(4);
>> + vulgar.setFirstDayOfWeek(Calendar.MONDAY);
>> +
>> + Assert.assertEquals(isoForm, printer.format(vulgar));
>> + }
>> +}
>>
>>
>
>
> --
> http://home.apache.org/~britter/
> http://twitter.com/BenediktRitter
> http://github.com/britter
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org