org.databene.commons.converter.LiteralParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of databene-commons Show documentation
Show all versions of databene-commons Show documentation
'databene commons' is an open source Java library by Volker Bergmann.
It provides extensions to the Java core library by utility classes, abstract concepts
and concrete implementations.
/*
* Copyright (C) 2004-2014 Volker Bergmann ([email protected]).
* 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 org.databene.commons.converter;
import java.sql.Time;
import java.util.Date;
import org.databene.commons.ConversionException;
import org.databene.commons.StringCharacterIterator;
import org.databene.commons.TimeUtil;
/**
* Parses the literal representation a simple type into an appropriate Java object of type
* Boolean, Integer, Long, Double, Date or String.
* Created: 19.03.2008 20:05:25
* @author Volker Bergmann
*/
public class LiteralParser extends ThreadSafeConverter {
public LiteralParser() {
super(String.class, Object.class);
}
// Converter interface implementation ------------------------------------------------------------------------------
@Override
public Object convert(String sourceValue) throws ConversionException {
return parse(sourceValue);
}
// static convenience methods --------------------------------------------------------------------------------------
/**
* parses a String into a date, number, boolean or String.
*
* content := boolean | date | number | unparsed
* boolean := 'true' | 'false'
* date := digit{4} '-' digit{2} '-' digit{2} ['T' digit{2} ':' digit{2} [':' digit{2} ['.' digit{1,3}]]]
* number := [-] digit* ['.' digit*]
*
* @param text
* @return a date, number, boolean or String that is the object representation of the specified text
*/
public static Object parse(String text) {
if (text == null || text.length() == 0)
return null;
String trimmed = text.trim();
if (trimmed.length() == 0)
return text;
// test for boolean
if ("true".equals(trimmed))
return Boolean.TRUE;
else if ("false".equals(trimmed))
return Boolean.FALSE;
// test for quoted string
if ((trimmed.startsWith("'") && trimmed.endsWith("'")) || (trimmed.startsWith("\"") && trimmed.endsWith("\"")))
return trimmed;
// precheck for unparsed
for (int i = 0; i < text.length(); i++) {
char c = text.charAt(i);
if (!(c == ':' || c == '-' || c == 'T' || c == '.' || (c >= '0' && c <= '9') || c == ' ' || c == '\t'))
return text;
}
// test for number or date
StringCharacterIterator iterator = new StringCharacterIterator(trimmed);
char c = iterator.next();
if (c == '-') {
Object number = parseNonNegativeNumber(iterator, true, false);
return (number != null ? number : text);
}
else if (c >= '0' && c <= '9') {
iterator.pushBack();
Object tmp = parseNonNegativeNumber(iterator, false, false);
if (tmp != null)
return tmp;
tmp = parseDate(trimmed);
if (tmp != null)
return tmp;
tmp = parseTime(trimmed);
if (tmp != null)
return tmp;
}
return trimmed;
}
// private helpers -------------------------------------------------------------------------------------------------
private static Object parseDate(String trimmed) {
StringCharacterIterator iterator = new StringCharacterIterator(trimmed);
// parse day
Long year = parseNonNegativeIntegerPart(iterator, true);
if (year == null || !iterator.hasNext() || iterator.next() != '-')
return null;
if (!iterator.hasNext())
return null;
Long month = parseNonNegativeIntegerPart(iterator, true);
if (month == null || !iterator.hasNext() || iterator.next() != '-')
return null;
if (!iterator.hasNext())
return null;
month = month - 1;
Long day = parseNonNegativeIntegerPart(iterator, true);
if (day == null || day == 0)
return null;
Date baseDate = TimeUtil.date(year.intValue(), month.intValue(), day.intValue());
if (!iterator.hasNext())
return baseDate;
if (iterator.next() != 'T')
return null;
if (!iterator.hasNext())
return null;
Object time = parseTime(iterator.remainingText());
return (time != null && time instanceof Time ? TimeUtil.add(baseDate, (Time) time) : null);
}
private static Object parseTime(String trimmed) {
StringCharacterIterator iterator = new StringCharacterIterator(trimmed);
// parse hours:minutes
Long hours = parseNonNegativeIntegerPart(iterator, true);
if (hours == null || !iterator.hasNext() || iterator.next() != ':')
return null;
Long minutes = parseNonNegativeIntegerPart(iterator, true);
if (minutes == null)
return null;
if (!iterator.hasNext())
return TimeUtil.time(hours.intValue(), minutes.intValue(), 0, 0);
// parse seconds
if (iterator.next() != ':')
return null;
Long seconds = parseNonNegativeIntegerPart(iterator, true);
if (seconds == null)
return null;
if (!iterator.hasNext())
return TimeUtil.time(hours.intValue(), minutes.intValue(), seconds.intValue(), 0);
// parse second fractions
if (iterator.next() != '.')
return null;
Double f = parseFraction(iterator);
if (f == null)
return null;
if (!iterator.hasNext())
return TimeUtil.time(hours.intValue(), minutes.intValue(), seconds.intValue(), (int)(f * 1000));
else
return trimmed;
}
private static Double parseFraction(StringCharacterIterator iterator) {
Double p = null;
Double base = 0.1;
while (iterator.hasNext()) {
char c = iterator.next();
if (c >= '0' && c <= '9') {
if (p == null)
p = 0.;
p += base * (c - '0');
} else {
iterator.pushBack();
return p;
}
base /= 10;
}
return p;
}
private static Long parseNonNegativeIntegerPart(StringCharacterIterator iterator, boolean leadingZeros) {
Long n = null;
int c = '0';
int digitCount = 0;
while (iterator.hasNext() && Character.isDigit(c = iterator.next())) {
digitCount++;
if (n == null)
n = 0L;
int d = (c - '0');
if (!leadingZeros && digitCount == 2 && n == 0)
return null; //
n = n * 10 + d;
c = -1;
}
if (c != -1)
iterator.pushBack();
return n;
}
private static Object parseNonNegativeNumber(StringCharacterIterator iterator, boolean negative, boolean leadingZeros) {
// parse integral number (part)
Long n = parseNonNegativeIntegerPart(iterator, leadingZeros);
if (n == null)
return null;
// handle numbers without fraction digits
if (!iterator.hasNext()) {
if (n > Integer.MAX_VALUE)
return (negative ? -n : n);
else
return (negative ? - n.intValue() : n.intValue());
} else {
if (iterator.next() == '.') {
if (!iterator.hasNext())
return (negative ? -(double) n : (double)n);
} else
return null;
}
// parse fraction
double p = n;
double base = 0.1;
while (iterator.hasNext()) {
char c = iterator.next();
if (c >= '0' && c <= '9')
p += base * (c - '0');
else
return null;
base /= 10;
}
return (negative ? -p : p);
}
}