001 /* 002 * Copyright (c) 2007-2015 Concurrent, 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 021 package cascading.tuple; 022 023 import java.beans.ConstructorProperties; 024 import java.lang.reflect.Type; 025 import java.util.Arrays; 026 import java.util.Iterator; 027 028 import cascading.tuple.coerce.Coercions; 029 import cascading.tuple.type.CoercibleType; 030 import cascading.util.ForeverValueIterator; 031 import org.slf4j.Logger; 032 import org.slf4j.LoggerFactory; 033 034 /** 035 * Class TupleEntry allows a {@link Tuple} instance and its declaring {@link Fields} instance to be used as a single object. 036 * <p/> 037 * Once a TupleEntry is created, its Fields cannot be changed, but the Tuple instance it holds can be replaced or 038 * modified. The managed Tuple should not have elements added or removed, as this will break the relationship with 039 * the associated Fields instance. 040 * <p/> 041 * If type information is provided on the Fields instance, all setters on this class will use that information to 042 * coerce the given object to the expected type. 043 * <p/> 044 * For example, if position is is of type {@code long}, then {@code entry.setString(0, "9" )} will coerce the "9" to a 045 * long {@code 9}. Thus, {@code entry.getObject(0) == 9l}. 046 * <p/> 047 * No coercion is performed with the {@link #getObject(Comparable)} and {@link #getObject(int)} methods. 048 * <p/> 049 * To set a value without coercion, see the {@link #setRaw(Comparable, Object)} and {@link #setRaw(int, Object)} 050 * methods. 051 * 052 * @see Fields 053 * @see Tuple 054 */ 055 public class TupleEntry 056 { 057 private static final Logger LOG = LoggerFactory.getLogger( TupleEntry.class ); 058 059 private static final CoercibleType[] EMPTY_COERCIONS = new CoercibleType[ 0 ]; 060 private static final ForeverValueIterator<CoercibleType> OBJECT_ITERATOR = new ForeverValueIterator<CoercibleType>( Coercions.OBJECT ); 061 062 /** An EMPTY TupleEntry instance for use as a stand in instead of a {@code null}. */ 063 public static final TupleEntry NULL = new TupleEntry( Fields.NONE, Tuple.NULL ); 064 065 /** Field fields */ 066 private Fields fields; 067 068 private CoercibleType[] coercions = EMPTY_COERCIONS; 069 070 /** Field isUnmodifiable */ 071 private boolean isUnmodifiable = false; 072 /** Field tuple */ 073 Tuple tuple; 074 075 /** 076 * Method select will select a new Tuple instance from the given set of entries. Entries order is significant to 077 * the selector. 078 * 079 * @param selector of type Fields 080 * @param entries of type TupleEntry 081 * @return Tuple 082 */ 083 public static Tuple select( Fields selector, TupleEntry... entries ) 084 { 085 // todo: consider just appending tuples values and just peeking those values 086 Tuple result = null; 087 088 // does not do field checks 089 if( selector.isAll() ) 090 { 091 for( TupleEntry entry : entries ) 092 { 093 if( result == null ) 094 result = entry.getTuple(); 095 else 096 result = result.append( entry.getTuple() ); 097 } 098 099 return result; 100 } 101 102 int size = 0; 103 104 for( TupleEntry entry : entries ) 105 size += entry.size(); 106 107 result = Tuple.size( selector.size() ); 108 109 int offset = 0; 110 111 for( TupleEntry entry : entries ) 112 { 113 for( int i = 0; i < selector.size(); i++ ) 114 { 115 Comparable field = selector.get( i ); 116 117 int pos; 118 119 if( field instanceof String ) 120 { 121 pos = entry.fields.indexOfSafe( field ); 122 123 if( pos == -1 ) 124 continue; 125 } 126 else 127 { 128 pos = entry.fields.translatePos( (Integer) field, size ) - offset; 129 130 if( pos >= entry.size() || pos < 0 ) 131 continue; 132 } 133 134 result.set( i, entry.getObject( pos ) ); // last in wins 135 } 136 137 offset += entry.size(); 138 } 139 140 return result; 141 } 142 143 /** Constructor TupleEntry creates a new TupleEntry instance. */ 144 public TupleEntry() 145 { 146 this.fields = Fields.NONE; 147 148 setCoercions(); 149 } 150 151 /** 152 * Constructor TupleEntry creates a new TupleEntry instance. 153 * 154 * @param isUnmodifiable of type boolean 155 */ 156 @ConstructorProperties({"isUnmodifiable"}) 157 public TupleEntry( boolean isUnmodifiable ) 158 { 159 this.fields = Fields.NONE; 160 this.isUnmodifiable = isUnmodifiable; 161 162 setCoercions(); 163 } 164 165 /** 166 * Constructor TupleEntry creates a new TupleEntry instance. 167 * 168 * @param fields of type Fields 169 */ 170 @ConstructorProperties({"fields"}) 171 public TupleEntry( Fields fields ) 172 { 173 this.fields = fields; 174 175 setCoercions(); 176 } 177 178 /** 179 * Constructor TupleEntry creates a new TupleEntry instance. 180 * 181 * @param fields of type Fields 182 * @param isUnmodifiable of type boolean 183 */ 184 @ConstructorProperties({"fields", "isUnmodifiable"}) 185 public TupleEntry( Fields fields, boolean isUnmodifiable ) 186 { 187 this.fields = fields; 188 this.isUnmodifiable = isUnmodifiable; 189 190 setCoercions(); 191 } 192 193 /** 194 * Constructor TupleEntry creates a new TupleEntry instance. 195 * 196 * @param fields of type Fields 197 * @param tuple of type Tuple 198 * @param isUnmodifiable of type boolean 199 */ 200 @ConstructorProperties({"fields", "tuple", "isUnmodifiable"}) 201 public TupleEntry( Fields fields, Tuple tuple, boolean isUnmodifiable ) 202 { 203 this.fields = fields; 204 this.isUnmodifiable = isUnmodifiable; 205 setTuple( tuple ); 206 207 setCoercions(); 208 } 209 210 /** 211 * Constructor TupleEntry creates a new TupleEntry instance. 212 * 213 * @param fields of type Fields 214 * @param tuple of type Tuple 215 */ 216 @ConstructorProperties({"fields", "tuple"}) 217 public TupleEntry( Fields fields, Tuple tuple ) 218 { 219 this.fields = fields; 220 this.tuple = tuple; 221 222 setCoercions(); 223 } 224 225 /** 226 * Constructor TupleEntry creates a new TupleEntry instance that is a safe copy of the given tupleEntry. 227 * <p/> 228 * The new instance is safe to cache and will be modifiable regardless of the given tupleEntry state. 229 * 230 * @param tupleEntry of type TupleEntry 231 */ 232 @ConstructorProperties({"tupleEntry"}) 233 public TupleEntry( TupleEntry tupleEntry ) 234 { 235 this.fields = tupleEntry.getFields(); 236 this.tuple = tupleEntry.getTupleCopy(); 237 238 setCoercions(); 239 } 240 241 /** 242 * Constructor TupleEntry creates a new TupleEntry instance. 243 * 244 * @param tuple of type Tuple 245 */ 246 @ConstructorProperties({"tuple"}) 247 public TupleEntry( Tuple tuple ) 248 { 249 this.fields = Fields.size( tuple.size() ); 250 this.tuple = tuple; 251 252 setCoercions(); 253 } 254 255 private void setCoercions() 256 { 257 if( coercions != EMPTY_COERCIONS ) 258 return; 259 260 coercions = getCoercions( getFields(), tuple ); 261 } 262 263 static CoercibleType[] getCoercions( Fields fields, Tuple tuple ) 264 { 265 Type[] types = fields.types; // safe to not get a copy 266 int size = fields.size(); 267 268 size = size == 0 && tuple != null ? tuple.size() : size; 269 270 if( size == 0 ) 271 return EMPTY_COERCIONS; 272 273 return Coercions.coercibleArray( size, types ); 274 } 275 276 /** 277 * Method isUnmodifiable returns true if this TupleEntry is unmodifiable. 278 * 279 * @return boolean 280 */ 281 public boolean isUnmodifiable() 282 { 283 return isUnmodifiable; 284 } 285 286 /** 287 * Method getFields returns the fields of this TupleEntry object. 288 * 289 * @return the fields (type Fields) of this TupleEntry object. 290 */ 291 public Fields getFields() 292 { 293 return fields; 294 } 295 296 /** 297 * Returns true if there are types associated with this instance. 298 * 299 * @return boolean 300 */ 301 public boolean hasTypes() 302 { 303 return fields.hasTypes(); 304 } 305 306 /** 307 * Method getTuple returns the tuple of this TupleEntry object. 308 * 309 * @return the tuple (type Tuple) of this TupleEntry object. 310 */ 311 public Tuple getTuple() 312 { 313 return tuple; 314 } 315 316 /** 317 * Method getTupleCopy returns a copy of the tuple of this TupleEntry object. 318 * 319 * @return a copy of the tuple (type Tuple) of this TupleEntry object. 320 */ 321 public Tuple getTupleCopy() 322 { 323 return new Tuple( tuple ); 324 } 325 326 /** 327 * Method getCoercedTuple is a helper method for copying the current tuple elements into a new Tuple, 328 * of the same size, as the requested coerced types. 329 * 330 * @param types of type Type[] 331 * @return returns the a new Tuple instance with coerced values 332 */ 333 public Tuple getCoercedTuple( Type[] types ) 334 { 335 return getCoercedTuple( types, Tuple.size( types.length ) ); 336 } 337 338 /** 339 * Method getCoercedTuple is a helper method for copying the current tuple elements into the new Tuple, 340 * of the same size, as the requested coerced types. 341 * 342 * @param types of type Type[] 343 * @param into of type Tuple 344 * @return returns the given into Tuple instance with coerced values 345 */ 346 public Tuple getCoercedTuple( Type[] types, Tuple into ) 347 { 348 if( into == null ) 349 throw new IllegalArgumentException( "into argument Tuple may not be null" ); 350 351 if( coercions.length != types.length || types.length != into.size() ) 352 throw new IllegalArgumentException( "current entry and given tuple and types must be same length" ); 353 354 for( int i = 0; i < coercions.length; i++ ) 355 { 356 Object element = tuple.getObject( i ); 357 into.set( i, Coercions.coerce( coercions[ i ], element, types[ i ] ) ); 358 } 359 360 return into; 361 } 362 363 /** 364 * Method setTuple sets the tuple of this TupleEntry object, no copy will be performed. 365 * <p/> 366 * If the given tuple is "unmodifiable" ({@code Tuple.isUnmodifiable() == true}) and this TupleEntry is 367 * not "unmodifiable", an exception will be thrown. 368 * <p/> 369 * Unmodifiable tuples are generally owned by the system and cannot be be changed and must not be cached. 370 * 371 * @param tuple the tuple of this TupleEntry object. 372 */ 373 public void setTuple( Tuple tuple ) 374 { 375 if( !isUnmodifiable && tuple != null && tuple.isUnmodifiable() ) 376 throw new IllegalArgumentException( "current entry is modifiable but given tuple is not modifiable, make copy of given Tuple first" ); 377 378 if( tuple != null && isUnmodifiable ) 379 this.tuple = Tuples.asUnmodifiable( tuple ); 380 else 381 this.tuple = tuple; 382 383 setCoercions(); 384 } 385 386 /** 387 * Method setCanonicalTuple replaces each value of the current tuple with the given tuple elements after 388 * they are coerced. 389 * <p/> 390 * This method will modify the existing Tuple wrapped by this TupleEntry instance even 391 * if it is marked as unmodifiable. 392 * <p/> 393 * If tuple argument is {@code null}, the current tuple will be set to {@code null}. 394 * 395 * @param tuple to replace the current wrapped Tuple instance 396 */ 397 public void setCanonicalTuple( Tuple tuple ) 398 { 399 if( tuple == null ) 400 { 401 this.tuple = null; 402 return; 403 } 404 405 if( isUnmodifiable ) 406 tuple = Tuples.asUnmodifiable( tuple ); 407 408 if( fields.size() != tuple.size() ) 409 throw new IllegalArgumentException( "current entry and given tuple must be same length" ); 410 411 for( int i = 0; i < coercions.length; i++ ) 412 { 413 Object element = tuple.getObject( i ); 414 415 this.tuple.set( i, coercions[ i ].canonical( element ) ); // force read type to the expected type 416 } 417 } 418 419 /** 420 * Method setCanonicalValues replaces each value of the current tuple with th give Object[] 421 * after they are coerced. 422 * 423 * @param values to replace the current wrapped tuple instance values 424 */ 425 public void setCanonicalValues( Object[] values ) 426 { 427 if( fields.size() != values.length ) 428 throw new IllegalArgumentException( "current entry and given array must be same length" ); 429 430 for( int i = 0; i < coercions.length; i++ ) 431 { 432 Object element = values[ i ]; 433 434 this.tuple.set( i, coercions[ i ].canonical( element ) ); // force read type to the expected type 435 } 436 } 437 438 /** 439 * Method size returns the number of values in this instance. 440 * 441 * @return int 442 */ 443 public int size() 444 { 445 return tuple.size(); 446 } 447 448 /** 449 * Method get returns the value in the given position pos. 450 * <p/> 451 * This method is deprecated, use {@link #getObject(int)} instead. 452 * 453 * @param pos position of the element to return. 454 * @return Comparable 455 */ 456 @Deprecated 457 public Comparable get( int pos ) 458 { 459 return tuple.get( pos ); 460 } 461 462 /** 463 * Method getObject returns the value in the given position pos. 464 * <p/> 465 * No coercion is performed if there is an associated coercible type. 466 * 467 * @param pos position of the element to return. 468 * @return Object 469 */ 470 public Object getObject( int pos ) 471 { 472 return tuple.getObject( pos ); 473 } 474 475 /** 476 * Method getObject returns the value in the given field or position as the requested type. 477 * <p/> 478 * Coercion is performed to the given type. 479 * 480 * @param pos position of the element to return. 481 * @return Object 482 */ 483 public Object getObject( int pos, Type type ) 484 { 485 return Coercions.coerce( coercions[ pos ], tuple.getObject( pos ), type ); 486 } 487 488 /** 489 * Method get returns the value in the given field or position. 490 * <br/> 491 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 492 * be considered. 493 * <p/> 494 * This method is deprecated, use {@link #getObject(Comparable)} instead. 495 * 496 * @param fieldName field name or position to return 497 * @return Comparable 498 */ 499 @Deprecated 500 public Comparable get( Comparable fieldName ) 501 { 502 return tuple.get( fields.getPos( asFieldName( fieldName ) ) ); 503 } 504 505 /** 506 * Method getObject returns the value in the given field or position. 507 * <br/> 508 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 509 * be considered. 510 * <p/> 511 * No coercion is performed if there is an associated coercible type. 512 * 513 * @param fieldName field name or position to return 514 * @return Comparable 515 */ 516 public Object getObject( Comparable fieldName ) 517 { 518 int pos = fields.getPos( asFieldName( fieldName ) ); 519 return tuple.getObject( pos ); 520 } 521 522 /** 523 * Method getObject returns the value in the given field or position as the requested type. 524 * <br/> 525 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 526 * be considered. 527 * <p/> 528 * Coercion is performed to the given type. 529 * 530 * @param fieldName field name or position to return 531 * @return Comparable 532 */ 533 public Object getObject( Comparable fieldName, Type type ) 534 { 535 int pos = fields.getPos( asFieldName( fieldName ) ); 536 return Coercions.coerce( coercions[ pos ], tuple.getObject( pos ), type ); 537 } 538 539 /** 540 * Method set sets the value in the given field or position. 541 * <p/> 542 * This method is deprecated in favor of {@link #setRaw(Comparable, Object)} 543 * 544 * @param fieldName field name or position to set 545 * @param value of type Comparable 546 */ 547 @Deprecated 548 public void set( Comparable fieldName, Object value ) 549 { 550 tuple.set( fields.getPos( asFieldName( fieldName ) ), value ); 551 } 552 553 /** 554 * Method set sets the value in the given position. 555 * <p/> 556 * No coercion is performed if there is an associated coercible type. 557 * 558 * @param pos position to set 559 * @param value of type Comparable 560 */ 561 public void setRaw( int pos, Object value ) 562 { 563 tuple.set( pos, value ); 564 } 565 566 /** 567 * Method set sets the value in the given field or position. 568 * <p/> 569 * No coercion is performed if there is an associated coercible type. 570 * 571 * @param fieldName field name or position to set 572 * @param value of type Comparable 573 */ 574 public void setRaw( Comparable fieldName, Object value ) 575 { 576 tuple.set( fields.getPos( asFieldName( fieldName ) ), value ); 577 } 578 579 /** 580 * Method set sets the value in the given field or position. 581 * 582 * @param fieldName field name or position to set 583 * @param value of type Comparable 584 */ 585 public void setObject( Comparable fieldName, Object value ) 586 { 587 int pos = fields.getPos( asFieldName( fieldName ) ); 588 589 tuple.set( pos, coercions[ pos ].canonical( value ) ); 590 } 591 592 /** 593 * Method setBoolean sets the value in the given field or position. 594 * 595 * @param fieldName field name or position to set 596 * @param value of type boolean 597 */ 598 public void setBoolean( Comparable fieldName, boolean value ) 599 { 600 int pos = fields.getPos( asFieldName( fieldName ) ); 601 602 tuple.set( pos, coercions[ pos ].canonical( value ) ); 603 } 604 605 /** 606 * Method setShort sets the value in the given field or position. 607 * 608 * @param fieldName field name or position to set 609 * @param value of type short 610 */ 611 public void setShort( Comparable fieldName, short value ) 612 { 613 int pos = fields.getPos( asFieldName( fieldName ) ); 614 615 tuple.set( pos, coercions[ pos ].canonical( value ) ); 616 } 617 618 /** 619 * Method setInteger sets the value in the given field or position. 620 * 621 * @param fieldName field name or position to set 622 * @param value of type int 623 */ 624 public void setInteger( Comparable fieldName, int value ) 625 { 626 int pos = fields.getPos( asFieldName( fieldName ) ); 627 628 tuple.set( pos, coercions[ pos ].canonical( value ) ); 629 } 630 631 /** 632 * Method setLong sets the value in the given field or position. 633 * 634 * @param fieldName field name or position to set 635 * @param value of type long 636 */ 637 public void setLong( Comparable fieldName, long value ) 638 { 639 int pos = fields.getPos( asFieldName( fieldName ) ); 640 641 tuple.set( pos, coercions[ pos ].canonical( value ) ); 642 } 643 644 /** 645 * Method setFloat sets the value in the given field or position. 646 * 647 * @param fieldName field name or position to set 648 * @param value of type float 649 */ 650 public void setFloat( Comparable fieldName, float value ) 651 { 652 int pos = fields.getPos( asFieldName( fieldName ) ); 653 654 tuple.set( pos, coercions[ pos ].canonical( value ) ); 655 } 656 657 /** 658 * Method setDouble sets the value in the given field or position. 659 * 660 * @param fieldName field name or position to set 661 * @param value of type double 662 */ 663 public void setDouble( Comparable fieldName, double value ) 664 { 665 int pos = fields.getPos( asFieldName( fieldName ) ); 666 667 tuple.set( pos, coercions[ pos ].canonical( value ) ); 668 } 669 670 /** 671 * Method setString sets the value in the given field or position. 672 * 673 * @param fieldName field name or position to set 674 * @param value of type String 675 */ 676 public void setString( Comparable fieldName, String value ) 677 { 678 int pos = fields.getPos( asFieldName( fieldName ) ); 679 tuple.set( pos, coercions[ pos ].canonical( value ) ); 680 } 681 682 /** 683 * Method getString returns the element for the given field name or position as a String. 684 * <br/> 685 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 686 * be considered. 687 * 688 * @param fieldName field name or position to return 689 * @return String 690 */ 691 public String getString( Comparable fieldName ) 692 { 693 return (String) getObject( fieldName, String.class ); 694 } 695 696 /** 697 * Method getFloat returns the element for the given field name or position as a float. Zero if null. 698 * <br/> 699 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 700 * be considered. 701 * 702 * @param fieldName field name or position to return 703 * @return float 704 */ 705 public float getFloat( Comparable fieldName ) 706 { 707 return (Float) getObject( fieldName, float.class ); 708 } 709 710 /** 711 * Method getDouble returns the element for the given field name or position as a double. Zero if null. 712 * <br/> 713 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 714 * be considered. 715 * 716 * @param fieldName field name or position to return 717 * @return double 718 */ 719 public double getDouble( Comparable fieldName ) 720 { 721 return (Double) getObject( fieldName, double.class ); 722 } 723 724 /** 725 * Method getInteger returns the element for the given field name or position as an int. Zero if null. 726 * <br/> 727 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 728 * be considered. 729 * 730 * @param fieldName field name or position to return 731 * @return int 732 */ 733 public int getInteger( Comparable fieldName ) 734 { 735 return (Integer) getObject( fieldName, int.class ); 736 } 737 738 /** 739 * Method getLong returns the element for the given field name or position as a long. Zero if null. 740 * <br/> 741 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 742 * be considered. 743 * 744 * @param fieldName field name or position to return 745 * @return long 746 */ 747 public long getLong( Comparable fieldName ) 748 { 749 return (Long) getObject( fieldName, long.class ); 750 } 751 752 /** 753 * Method getShort returns the element for the given field name or position as a short. Zero if null. 754 * <br/> 755 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 756 * be considered. 757 * 758 * @param fieldName field name or position to return 759 * @return short 760 */ 761 public short getShort( Comparable fieldName ) 762 { 763 return (Short) getObject( fieldName, short.class ); 764 } 765 766 /** 767 * Method getBoolean returns the element for the given field name or position as a boolean. 768 * If the value is (case ignored) the string 'true', a {@code true} value will be returned. {@code false} if null. 769 * <br/> 770 * {@code fieldName} may optionally be a {@link Fields} instance. Only the first field name or position will 771 * be considered. 772 * 773 * @param fieldName field name or position to return 774 * @return boolean 775 */ 776 public boolean getBoolean( Comparable fieldName ) 777 { 778 return (Boolean) getObject( fieldName, boolean.class ); 779 } 780 781 private Comparable asFieldName( Comparable fieldName ) 782 { 783 return Fields.asFieldName( fieldName ); 784 } 785 786 /** 787 * Method selectEntry selects the fields specified in the selector from this instance. If {@link Fields#ALL} or the 788 * same fields as declared are given, {@code this} will be returned. 789 * <p/> 790 * The returned TupleEntry will be either modifiable or unmodifiable, depending on the state of this TupleEntry instance. 791 * <p/> 792 * See {@link #selectEntryCopy(Fields)} to guarantee a copy suitable for modifying or caching/storing in a collection. 793 * <p/> 794 * Note this is a bug fix and change from 2.0 and 2.1. In previous versions the modifiable state was dependent 795 * on the given selector. 796 * 797 * @param selector Fields selector that selects the values to return 798 * @return TupleEntry 799 */ 800 public TupleEntry selectEntry( Fields selector ) 801 { 802 if( selector == null || selector.isAll() || fields == selector ) // == is intentional 803 return this; 804 805 if( selector.isNone() ) 806 return isUnmodifiable ? TupleEntry.NULL : new TupleEntry(); 807 808 return new TupleEntry( Fields.asDeclaration( selector ), tuple.get( this.fields, selector ), isUnmodifiable ); 809 } 810 811 /** 812 * Method selectEntry selects the fields specified in selector from this instance. 813 * <p/> 814 * It is guaranteed to return a new modifiable TupleEntry instance at a cost of copying data. 815 * <p/> 816 * The returned instance is safe to cache. 817 * 818 * @param selector Fields selector that selects the values to return 819 * @return TupleEntry 820 */ 821 public TupleEntry selectEntryCopy( Fields selector ) 822 { 823 if( selector == null || selector.isAll() || fields == selector ) // == is intentional 824 return new TupleEntry( this ); 825 826 if( selector.isNone() ) 827 return new TupleEntry(); 828 829 return new TupleEntry( Fields.asDeclaration( selector ), tuple.get( this.fields, selector ) ); 830 } 831 832 /** 833 * Method selectTuple selects the fields specified in the selector from this instance. If {@link Fields#ALL} or the 834 * same fields as declared are given, {@code this.getTuple()} will be returned. 835 * <p/> 836 * The returned Tuple will be either modifiable or unmodifiable, depending on the state of this TupleEntry instance. 837 * <p/> 838 * See {@link #selectTupleCopy(Fields)} to guarantee a copy suitable for modifying or caching/storing in a collection. 839 * <p/> 840 * Note this is a bug fix and change from 2.0 and 2.1. In previous versions the modifiable state was dependent 841 * on the given selector. 842 * 843 * @param selector Fields selector that selects the values to return 844 * @return Tuple 845 */ 846 public Tuple selectTuple( Fields selector ) 847 { 848 if( selector == null || selector.isAll() || fields == selector ) // == is intentional 849 return this.tuple; 850 851 if( selector.isNone() ) 852 return Tuple.NULL; 853 854 Tuple result = tuple.get( fields, selector ); 855 856 if( isUnmodifiable ) 857 Tuples.asUnmodifiable( result ); 858 859 return result; 860 } 861 862 /** 863 * Method selectTupleCopy selects the fields specified in selector from this instance. 864 * <p/> 865 * It is guaranteed to return a new modifiable Tuple instance at a cost of copying data. 866 * <p/> 867 * The returned instance is safe to cache. 868 * 869 * @param selector Fields selector that selects the values to return 870 * @return Tuple 871 */ 872 public Tuple selectTupleCopy( Fields selector ) 873 { 874 if( selector == null || selector.isAll() || fields == selector ) // == is intentional 875 return new Tuple( this.tuple ); 876 877 if( selector.isNone() ) 878 return new Tuple(); 879 880 return tuple.get( fields, selector ); 881 } 882 883 /** 884 * Method selectInto selects the fields specified in the selector from this instance and copies 885 * them into the given tuple argument. 886 * 887 * @param selector of type Fields 888 * @param tuple of type Tuple 889 * @return returns the given tuple argument with new values added 890 */ 891 public Tuple selectInto( Fields selector, Tuple tuple ) 892 { 893 if( selector.isNone() ) 894 return tuple; 895 896 int[] pos = this.tuple.getPos( fields, selector ); 897 898 if( pos == null || pos.length == 0 ) 899 { 900 tuple.addAll( this.tuple ); 901 } 902 else 903 { 904 for( int i : pos ) 905 tuple.add( this.tuple.getObject( i ) ); 906 } 907 908 return tuple; 909 } 910 911 /** 912 * Method setTuple sets the values specified by the selector to the values given by the given tuple, the given 913 * values will always be copied into this TupleEntry. 914 * 915 * @param selector of type Fields 916 * @param tuple of type Tuple 917 */ 918 public void setTuple( Fields selector, Tuple tuple ) 919 { 920 if( selector == null || selector.isAll() ) 921 this.tuple.setAll( tuple ); 922 else 923 this.tuple.set( fields, selector, tuple ); 924 } 925 926 /** 927 * Method set sets the values from the given tupleEntry into this TupleEntry instance based on the given 928 * tupleEntry field names. 929 * <p/> 930 * If type information is given, each incoming value will be coerced from its canonical type to the current type. 931 * 932 * @param tupleEntry of type TupleEntry 933 */ 934 public void set( TupleEntry tupleEntry ) 935 { 936 this.tuple.set( fields, tupleEntry.getFields(), tupleEntry.getTuple(), tupleEntry.coercions ); 937 } 938 939 /** 940 * Method appendNew appends the given TupleEntry instance to this instance. 941 * 942 * @param entry of type TupleEntry 943 * @return TupleEntry 944 */ 945 public TupleEntry appendNew( TupleEntry entry ) 946 { 947 Fields appendedFields = fields.append( entry.fields.isUnknown() ? Fields.size( entry.tuple.size() ) : entry.fields ); 948 Tuple appendedTuple = tuple.append( entry.tuple ); 949 950 return new TupleEntry( appendedFields, appendedTuple ); 951 } 952 953 @Override 954 public boolean equals( Object object ) 955 { 956 if( this == object ) 957 return true; 958 959 if( !( object instanceof TupleEntry ) ) 960 return false; 961 962 TupleEntry that = (TupleEntry) object; 963 964 if( fields != null ? !fields.equals( that.fields ) : that.fields != null ) 965 return false; 966 967 // use comparators if in the this side fields instance 968 if( tuple != null ? fields.compare( tuple, that.tuple ) != 0 : that.tuple != null ) 969 return false; 970 971 return true; 972 } 973 974 @Override 975 public int hashCode() 976 { 977 int result = fields != null ? fields.hashCode() : 0; 978 result = 31 * result + ( tuple != null ? tuple.hashCode() : 0 ); 979 return result; 980 } 981 982 @Override 983 public String toString() 984 { 985 if( fields == null ) 986 return "empty"; 987 else if( tuple == null ) 988 return "fields: " + fields.print(); 989 else 990 return "fields: " + fields.print() + " tuple: " + tuple.print(); 991 } 992 993 /** 994 * Method asIterableOf returns an {@link Iterable} instance that will coerce all Tuple elements 995 * into the given {@code type} parameter. 996 * <p/> 997 * This method honors any {@link cascading.tuple.type.CoercibleType} instances on the internal 998 * Fields instance for the specified Tuple element. 999 * 1000 * @param type of type Class 1001 * @return an Iterable 1002 */ 1003 public <T> Iterable<T> asIterableOf( final Class<T> type ) 1004 { 1005 return new Iterable<T>() 1006 { 1007 @Override 1008 public Iterator<T> iterator() 1009 { 1010 final Iterator<CoercibleType> coercibleIterator = coercions.length == 0 ? 1011 OBJECT_ITERATOR : 1012 Arrays.asList( coercions ).iterator(); 1013 1014 final Iterator valuesIterator = tuple.iterator(); 1015 1016 return new Iterator<T>() 1017 { 1018 @Override 1019 public boolean hasNext() 1020 { 1021 return valuesIterator.hasNext(); 1022 } 1023 1024 @Override 1025 public T next() 1026 { 1027 Object next = valuesIterator.next(); 1028 1029 return (T) coercibleIterator.next().coerce( next, type ); 1030 } 1031 1032 @Override 1033 public void remove() 1034 { 1035 valuesIterator.remove(); 1036 } 1037 }; 1038 } 1039 }; 1040 } 1041 }