001/*
002 * Copyright (c) 2007-2017 Xplenty, Inc. All Rights Reserved.
003 *
004 * Project and contact information: http://www.cascading.org/
005 *
006 * This file is part of the Cascading project.
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *     http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020
021package cascading.pipe.assembly;
022
023import java.beans.ConstructorProperties;
024
025import cascading.operation.Identity;
026import cascading.pipe.Each;
027import cascading.pipe.Pipe;
028import cascading.pipe.SubAssembly;
029import cascading.tuple.Fields;
030
031/**
032 * Class Coerce is a {@link SubAssembly} that will coerce all incoming {@link cascading.tuple.Tuple} values to
033 * the given types.
034 * <p/>
035 * If the given type is a primitive ({@code long}), and the tuple value is null, {@code 0} is returned.
036 * If the type is an Object ({@code java.lang.Long}), and the tuple value is {@code null}, {@code null} is returned.
037 * <p/>
038 * Coerce encapsulates the {@link Identity} function.
039 * <p/>
040 * Note if the resolved coerceFields size does not equal the number of given types there will be a
041 * runtime error during execution.
042 *
043 * @see cascading.pipe.SubAssembly
044 * @see cascading.operation.Identity
045 */
046public class Coerce extends SubAssembly
047  {
048  /**
049   * Constructor Coerce creates a new Coerce instance that will coerce all input Tuple values.
050   * <p/>
051   * Note if the resolved coerceFields size does not equal the number of given types there will be a
052   * runtime error during execution. Declaring the fields that must be coerced is a suggested practice.
053   *
054   * @param previous of type Pipe
055   * @param types    of type Class...
056   */
057  @ConstructorProperties({"previous", "types"})
058  public Coerce( Pipe previous, Class... types )
059    {
060    super( previous );
061
062    if( types.length == 0 )
063      throw new IllegalArgumentException( "given types array may not be zero length" );
064
065    setTails( new Each( previous, new Identity( types ) ) );
066    }
067
068  /**
069   * Constructor Coerce creates a new Coerce instance that will only coerce the given coerceFields Tuple values.
070   * <p/>
071   * Note the resulting output Tuple will contain all the original incoming Fields.
072   * <p/>
073   * Also note if the resolved coerceFields size does not equal the number of given types there will be a
074   * runtime error during execution.
075   *
076   * @param previous     of type Pipe
077   * @param coerceFields of type Fields
078   * @param types        of type Class...
079   */
080  @ConstructorProperties({"previous", "coerceFields", "types"})
081  public Coerce( Pipe previous, Fields coerceFields, Class... types )
082    {
083    super( previous );
084
085    if( coerceFields == null )
086      throw new IllegalArgumentException( "coerceFields may not be null" );
087
088    if( types.length == 0 )
089      throw new IllegalArgumentException( "given types array may not be zero length" );
090
091    setTails( new Each( previous, coerceFields, new Identity( types ), Fields.REPLACE ) );
092    }
093
094  /**
095   * Constructor Coerce creates a new Coerce instance that will only coerce the given coerceFields Tuple values.
096   * <p/>
097   * The given {@code coerceFields} instance must contain field type information, otherwise an
098   * {@link IllegalArgumentException} will be thrown.
099   * <p/>
100   * Note the resulting output Tuple will contain all the original incoming Fields.
101   *
102   * @param previous     of type Pipe
103   * @param coerceFields of type Fields
104   */
105  @ConstructorProperties({"previous", "coerceFields"})
106  public Coerce( Pipe previous, Fields coerceFields )
107    {
108    super( previous );
109
110    if( coerceFields == null )
111      throw new IllegalArgumentException( "coerceFields may not be null" );
112
113    if( !coerceFields.hasTypes() )
114      throw new IllegalArgumentException( "coerceFields must have field types declared" );
115
116    setTails( new Each( previous, coerceFields, new Identity( coerceFields ), Fields.REPLACE ) );
117
118    if( coerceFields.getTypes().length == 0 )
119      throw new IllegalArgumentException( "number of types must not be zero" );
120    }
121  }