001// Copyright 2010 The Apache Software Foundation 002// 003// Licensed under the Apache License, Version 2.0 (the "License"); 004// you may not use this file except in compliance with the License. 005// You may obtain a copy of the License at 006// 007// http://www.apache.org/licenses/LICENSE-2.0 008// 009// Unless required by applicable law or agreed to in writing, software 010// distributed under the License is distributed on an "AS IS" BASIS, 011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012// See the License for the specific language governing permissions and 013// limitations under the License. 014 015package org.apache.tapestry5.func; 016 017import java.util.Objects; 018 019/** 020 * A Tuple holds two values of two different types. 021 * 022 * @param <A> first type 023 * @param <B> second type 024 * @since 5.3 025 */ 026public class Tuple<A, B> 027{ 028 public final A first; 029 030 public final B second; 031 032 public Tuple(A first, B second) 033 { 034 this.first = first; 035 this.second = second; 036 } 037 038 public static <X, Y> Tuple<X, Y> create(X first, Y second) 039 { 040 return new Tuple<X, Y>(first, second); 041 } 042 043 /** 044 * Returns the values of the tuple, separated by commas, enclosed in parenthesis. Example: 045 * <code>("Ace", "Spades")</code>. 046 */ 047 @Override 048 public String toString() 049 { 050 StringBuilder builder = new StringBuilder("("); 051 052 builder.append(String.valueOf(first)); 053 builder.append(", "); 054 builder.append(String.valueOf(second)); 055 056 extendDescription(builder); 057 058 return builder.append(')').toString(); 059 } 060 061 /** 062 * Overriden in subclasses to write additional values into the 063 * description. 064 * 065 * @param builder 066 */ 067 protected void extendDescription(StringBuilder builder) 068 { 069 } 070 071 /** Utility for comparing two values, either of which may be null. */ 072 static boolean isEqual(Object left, Object right) 073 { 074 return left == right || (left != null && left.equals(right)); 075 } 076 077 /** 078 * Compares this Tuple to another object. Equality is defined by: other object is not null, 079 * is same class as this Tuple, and all values are themselves equal. 080 */ 081 @Override 082 public boolean equals(Object obj) 083 { 084 if (obj == this) 085 return true; 086 087 if (obj == null || !(obj.getClass() == getClass())) 088 return false; 089 090 return isMatch(obj); 091 } 092 093 /** 094 * Returns a hash code value for the tuple, based on its values. 095 * 096 * @return a hash code value for this tuple. 097 * @since 5.7 098 */ 099 @Override 100 public int hashCode() 101 { 102 return Objects.hash(this.first, this.second); 103 } 104 105 /** 106 * The heart of {@link #equals(Object)}; the other object is the same class as this object. 107 * 108 * @param other 109 * other tuple to compare 110 * @return true if all values stored in tuple match 111 */ 112 protected boolean isMatch(Object other) 113 { 114 Tuple<?, ?> tuple = (Tuple<?, ?>) other; 115 116 return isEqual(first, tuple.first) && isEqual(second, tuple.second); 117 } 118}