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