<commit_before>//
// Depot library - a Java relational persistence library
// http://code.google.com/p/depot/source/browse/trunk/LICENSE

package com.samskivert.depot.impl;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;

import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;

import com.samskivert.depot.DatabaseException;
import com.samskivert.depot.PersistentRecord;
import com.samskivert.depot.Transformer;
import com.samskivert.depot.annotation.Column;
import com.samskivert.depot.annotation.Computed;
import com.samskivert.depot.annotation.GeneratedValue;
import com.samskivert.depot.annotation.Transform;
import com.samskivert.jdbc.ColumnDefinition;

import com.samskivert.util.ByteEnum;
import com.samskivert.util.ByteEnumUtil;
import com.samskivert.util.Logger;
import com.samskivert.util.StringUtil;

import static com.google.common.base.Preconditions.checkArgument;

/**
 * Handles the marshalling and unmarshalling of a particular field of a persistent object.
 *
 * @see DepotMarshaller
 */
public abstract class FieldMarshaller<T>
{
    /** Used by the {@link SQLBuilder} implementations. We factor this into an interface to avoid a
     * bunch of instanceof casts and to ensure that if a new supported type is added, all of the
     * builders will fail to compile instead of failing at runtime. */
    public static interface ColumnTyper {
        String getBooleanType (int length);
        String getByteType (int length);
        String getShortType (int length);
        String getIntType (int length);
        String getLongType (int length);
        String getFloatType (int length);
        String getDoubleType (int length);
        String getStringType (int length);
        String getDateType (int length);
        String getTimeType (int length);
        String getTimestampType (int length);
        String getBlobType (int length);
        String getClobType (int length);
    }

    /**
     * Creates and returns a field marshaller for the specified field. Throws an exception if the
     * field in question cannot be marshalled.
     */
    public static FieldMarshaller<?> createMarshaller (Field field)
    {
        // first, look for a @Transform annotation on the field (cheap)
        Transform xform = field.getAnnotation(Transform.class);
        if (xform == null) {
            // next look for a marshaller for the basic type (cheapish)
            FieldMarshaller<?> marshaller = createMarshaller(field.getType());
            if (marshaller != null) {
                marshaller.create(field);
                return marshaller;
            }

            // finally look for an @Transform annotation on the field type (expensive)
            xform = findTransformAnnotation(field.getType());
            checkArgument(xform != null, "Cannot marshall " + field + ".");
        }

        try {
            // weirdly if we inline the xformer creation into the createTransformingMarshaller
            // call, we get a type error; must be some subtlety of wildcard capture...
            Transformer<?, ?> xformer = xform.value().newInstance();
            return createTransformingMarshaller(xformer, field, xform);
        } catch (InstantiationException e) {
            throw new IllegalArgumentException(
                Logger.format("Unable to create Transformer", "xclass", xform.value(),
                              "field", field), e);
        } catch (IllegalAccessException e) {
            throw new IllegalArgumentException(
                Logger.format("Unable to create Transformer", "xclass", xform.value(),
                              "field", field), e);
        }
    }

    protected static <F,T> FieldMarshaller<F> createTransformingMarshaller (
        final Transformer<F,T> xformer, Field field, Transform annotation)
    {
        Class<?> pojoType = getTransformerType(xformer, "from");
        checkArgument(pojoType.isAssignableFrom(field.getType()),
                      "@Transform error on %s.%s: %s cannot convert %s", field.getType().getName(),
                      field.getName(), xformer.getClass().getName(), field.getType().getName());
        xformer.init(field.getGenericType(), annotation);

        @SuppressWarnings("unchecked") final FieldMarshaller<T> delegate =
            (FieldMarshaller<T>)createMarshaller(getTransformerType(xformer, "to"));<commit_msg>Improve the semantics of @Transform handling.<commit_after>//
// Depot library - a Java relational persistence library
// http://code.google.com/p/depot/source/browse/trunk/LICENSE

package com.samskivert.depot.impl;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;

import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;

import com.samskivert.depot.DatabaseException;
import com.samskivert.depot.PersistentRecord;
import com.samskivert.depot.Transformer;
import com.samskivert.depot.annotation.Column;
import com.samskivert.depot.annotation.Computed;
import com.samskivert.depot.annotation.GeneratedValue;
import com.samskivert.depot.annotation.Transform;
import com.samskivert.jdbc.ColumnDefinition;

import com.samskivert.util.ByteEnum;
import com.samskivert.util.ByteEnumUtil;
import com.samskivert.util.Logger;
import com.samskivert.util.StringUtil;

import static com.google.common.base.Preconditions.checkArgument;

/**
 * Handles the marshalling and unmarshalling of a particular field of a persistent object.
 *
 * @see DepotMarshaller
 */
public abstract class FieldMarshaller<T>
{
    /** Used by the {@link SQLBuilder} implementations. We factor this into an interface to avoid a
     * bunch of instanceof casts and to ensure that if a new supported type is added, all of the
     * builders will fail to compile instead of failing at runtime. */
    public static interface ColumnTyper {
        String getBooleanType (int length);
        String getByteType (int length);
        String getShortType (int length);
        String getIntType (int length);
        String getLongType (int length);
        String getFloatType (int length);
        String getDoubleType (int length);
        String getStringType (int length);
        String getDateType (int length);
        String getTimeType (int length);
        String getTimestampType (int length);
        String getBlobType (int length);
        String getClobType (int length);
    }

    /**
     * Creates and returns a field marshaller for the specified field. Throws an exception if the
     * field in question cannot be marshalled.
     */
    public static FieldMarshaller<?> createMarshaller (Field field)
    {
        // first, look for a @Transform annotation on the field (cheap)
        Transform xform = field.getAnnotation(Transform.class);
        if (xform == null) {
            // next look for an @Transform annotation on the field type; we only do this if it's a
            // non-primitive/non-string type because this search is somewhat expensive
            Class<?> ftype = field.getType();
            if (!ftype.isPrimitive() && !ftype.equals(String.class)) {
                xform = findTransformAnnotation(field.getType());
            }
        }

        // if we found a transform annotation, create a transforming marshaller
        if (xform != null) {
            try {
                // weirdly if we inline the xformer creation into the createTransformingMarshaller
                // call, we get a type error; must be some subtlety of wildcard capture...
                Transformer<?, ?> xformer = xform.value().newInstance();
                return createTransformingMarshaller(xformer, field, xform);
            } catch (InstantiationException e) {
                throw new IllegalArgumentException(
                    Logger.format("Unable to create Transformer", "xclass", xform.value(),
                                  "field", field), e);
            } catch (IllegalAccessException e) {
                throw new IllegalArgumentException(
                    Logger.format("Unable to create Transformer", "xclass", xform.value(),
                                  "field", field), e);
            }
        }

        // last look for a marshaller for the basic type (cheapish)
        FieldMarshaller<?> marshaller = createMarshaller(field.getType());
        if (marshaller != null) {
            marshaller.create(field);
            return marshaller;
        }

        // at this point we must throw up our hands
        throw new IllegalArgumentException("Cannot marshall " + field + ".");
    }

    protected static <F,T> FieldMarshaller<F> createTransformingMarshaller (
        final Transformer<F,T> xformer, Field field, Transform annotation)
    {
        Class<?> pojoType = getTransformerType(xformer, "from");
        checkArgument(pojoType.isAssignableFrom(field.getType()),
                      "@Transform error on %s.%s: %s cannot convert %s", field.getType().getName(),
                      field.getName(), xformer.getClass().getName(), field.getType().getName());
        xformer.init(field.getGenericType(), annotation);

        @SuppressWarnings("unchecked") final FieldMarshaller<T> delegate =
            (FieldMarshaller<T>)createMarshaller(getTransformerType(xformer, "to"));
{'fraction_non_alphanumeric': 0.09595327492699207, 'fraction_numerical': 0.0, 'mean_word_length': 2.8142402545743836, 'pattern_counts': {'":': 0, '<': 24, '<?xml version=': 0, '>': 24, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3520729', 'n_tokens_mistral': 2555, 'n_tokens_neox': 2549, 'n_words': 763}