blob: 7ce856c559ba600dd999b66151192af48014474f [file] [log] [blame]
/*
* 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.sis.internal.converter;
import java.util.Date;
import java.util.Set;
import java.util.EnumSet;
import org.apache.sis.util.ObjectConverter;
import org.apache.sis.math.FunctionProperty;
/**
* Handles conversions from {@link Date} to various objects.
*
* <div class="section">String representation</div>
* There is currently no converter between {@link String} and {@link java.util.Date} because the
* date format is not yet defined (we are considering the ISO format for a future SIS version).
*
* <div class="section">Special cases</div>
* The converter from dates to timestamps is not injective, because the same date could be mapped
* to many timestamps since timestamps have an additional nanoseconds field.
*
* <div class="section">Immutability and thread safety</div>
* This base class and all inner classes are immutable, and thus inherently thread-safe.
*
* @author Martin Desruisseaux (Geomatys)
* @version 0.3
* @since 0.3
* @module
*/
abstract class DateConverter<T> extends SystemConverter<Date,T> {
/**
* For cross-version compatibility.
*/
private static final long serialVersionUID = 945435736679371963L;
/**
* The inverse converter. Must be initialized by subclass constructors.
*/
SystemConverter<T, Date> inverse;
/**
* Creates a converter for the given target type.
* Subclasses must initialize {@link #inverse}.
*/
DateConverter(final Class<T> targetClass) {
super(Date.class, targetClass);
}
/**
* Returns the function properties.
*/
@Override
public Set<FunctionProperty> properties() {
return EnumSet.of(FunctionProperty.SURJECTIVE, FunctionProperty.ORDER_PRESERVING,
FunctionProperty.INVERTIBLE);
}
/**
* Returns the inverse converter.
*/
@Override
public final ObjectConverter<T, Date> inverse() {
return inverse;
}
/**
* Converter from {@code Long} to {@code Date}.
* This converter is <strong>not</strong> registered by {@link ConverterRegistry#initialize()}.
* Instead, {@link SystemRegistry} will fetch it when first needed by looking at the inverse
* of {@link DateConverter.Long}. The same is true for all inverse converters defined in the
* {@code DateConverter} enclosing class.
*/
private static final class Inverse extends SystemConverter<java.lang.Long, java.util.Date> {
private static final long serialVersionUID = 5022624034871426299L;
private final SystemConverter<java.util.Date, java.lang.Long> inverse;
Inverse(final SystemConverter<java.util.Date, java.lang.Long> inverse) {
super(java.lang.Long.class, java.util.Date.class);
this.inverse = inverse;
}
@Override public ObjectConverter<java.util.Date, java.lang.Long> inverse() {
return inverse;
}
@Override public ObjectConverter<java.lang.Long, Date> unique() {
return inverse.inverse();
}
@Override public Set<FunctionProperty> properties() {
return inverse.properties();
}
@Override public java.util.Date apply(final java.lang.Long target) {
return (target != null) ? new java.util.Date(target) : null;
}
}
/**
* Converter from {@code Date} to {@code Long}.
*/
public static final class Long extends DateConverter<java.lang.Long> {
private static final long serialVersionUID = 5145114630594761657L;
public Long() { // Instantiated by ServiceLoader.
super(java.lang.Long.class);
inverse = new Inverse(this);
}
@Override public Set<FunctionProperty> properties() {
return bijective();
}
@Override public java.lang.Long apply(final Date source) {
return (source != null) ? source.getTime() : null;
}
}
/**
* From {@code Date} to SQL {@code Date}.
* The inverse of this converter is the identity conversion.
*/
public static final class SQL extends DateConverter<java.sql.Date> {
private static final long serialVersionUID = -7444502675467008640L;
public SQL() { // Instantiated by ServiceLoader.
super(java.sql.Date.class);
inverse = new IdentityConverter<>(targetClass, Date.class, this);
}
@Override public java.sql.Date apply(final Date source) {
if (source == null || source instanceof java.sql.Date) {
return (java.sql.Date) source;
}
return new java.sql.Date(source.getTime());
}
}
/**
* From {@code Date} to SQL {@code Timestamp}.
* The inverse of this converter is the identity conversion.
*/
public static final class Timestamp extends DateConverter<java.sql.Timestamp> {
private static final long serialVersionUID = 7629460512978844462L;
public Timestamp() { // Instantiated by ServiceLoader.
super(java.sql.Timestamp.class);
inverse = new IdentityConverter<>(targetClass, Date.class, this);
}
@Override public java.sql.Timestamp apply(final Date source) {
if (source == null || source instanceof java.sql.Timestamp) {
return (java.sql.Timestamp) source;
}
return new java.sql.Timestamp(source.getTime());
}
}
/*
* We do not yet provide converter to java.time.Instant. If we do so, we need to create an InstantConverter class
* doing the inverse conversion. Reminder: java.sql.Date and java.sql.Time are not convertible to Instant (their
* Date.toInstant() method throws UnsupportedOperationException), but java.sql.Timestamp is.
*
* If conversion to/from java.time.Instant is added, see if some code can be shared with
* org.apache.sis.filter.ComparisonFunction.
*/
}