• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

grpc / grpc-java / #20526

13 Oct 2026 04:06PM UTC coverage: 89.426% (-0.02%) from 89.449%
#20526

push

github

web-flow
core: Enable the new Pick First Leaf Loadbalancer (#13114)

39344 of 43996 relevant lines covered (89.43%)

0.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.89
/../api/src/main/java/io/grpc/Attributes.java
1
/*
2
 * Copyright 2015 The gRPC Authors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package io.grpc;
18

19
import static com.google.common.base.Preconditions.checkNotNull;
20

21
import com.google.common.base.Objects;
22
import java.util.Collections;
23
import java.util.IdentityHashMap;
24
import java.util.Map;
25
import java.util.Set;
26
import javax.annotation.Nullable;
27
import javax.annotation.concurrent.Immutable;
28

29
/**
30
 * An immutable type-safe container of attributes.
31
 *
32
 * <h3>Annotation semantics</h3>
33
 *
34
 * <p>As a convention, annotations such as {@link Grpc.TransportAttr} is defined to associate
35
 * attribute {@link Key}s and their propagation paths.  The annotation may be applied to a {@code
36
 * Key} definition field, a method that returns {@link Attributes}, or a variable of type {@link
37
 * Attributes}, to indicate that the annotated {@link Attributes} objects may contain the annotated
38
 * {@code Key}.
39
 *
40
 * <p>Javadoc users may click "USE" on the navigation bars of the annotation's javadoc page to view
41
 * references of such annotation.
42
 *
43
 * @since 1.13.0
44
 */
45
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/1764")
46
@Immutable
47
public final class Attributes {
48

49
  private final IdentityHashMap<Key<?>, Object> data;
50

51
  private static final IdentityHashMap<Key<?>, Object> EMPTY_MAP =
1 ✔
52
      new IdentityHashMap<Key<?>, Object>();
53
  public static final Attributes EMPTY = new Attributes(EMPTY_MAP);
1 ✔
54

55
  private Attributes(IdentityHashMap<Key<?>, Object> data) {
1 ✔
56
    assert data != null;
1 ✔
57
    this.data = data;
1 ✔
58
  }
1 ✔
59

60
  /**
61
   * Gets the value for the key, or {@code null} if it's not present.
62
   */
63
  @SuppressWarnings("unchecked")
64
  @Nullable
65
  public <T> T get(Key<T> key) {
66
    return (T) data.get(key);
1 ✔
67
  }
68

69
  /**
70
   * Returns set of keys stored in container.
71
   *
72
   * @return Set of Key objects.
73
   * @deprecated This method is being considered for removal, if you feel this method is needed
74
   *     please reach out on this Github issue:
75
   *     <a href="https://github.com/grpc/grpc-java/issues/1764">grpc-java/issues/1764</a>.
76
   */
77
  @Deprecated
78
  public Set<Key<?>> keys() {
79
    return Collections.unmodifiableSet(data.keySet());
×
80
  }
81

82
  Set<Key<?>> keysForTest() {
83
    return Collections.unmodifiableSet(data.keySet());
1 ✔
84
  }
85

86
  /**
87
   * Create a new builder that is pre-populated with the content from a given container.
88
   * @deprecated Use {@link Attributes#toBuilder()} on the {@link Attributes} instance instead.
89
   *     This method will be removed in the future.
90
   */
91
  @Deprecated
92
  public static Builder newBuilder(Attributes base) {
93
    checkNotNull(base, "base");
×
94
    return new Builder(base);
×
95
  }
96

97
  /**
98
   * Create a new builder.
99
   */
100
  public static Builder newBuilder() {
101
    return new Builder(EMPTY);
1 ✔
102
  }
103

104
  /**
105
   * Creates a new builder that is pre-populated with the content of this container.
106
   * @return a new builder.
107
   */
108
  public Builder toBuilder() {
109
    return new Builder(this);
1 ✔
110
  }
111

112
  /**
113
   * Key for an key-value pair. Uses reference equality.
114
   *
115
   * @param <T> type of the value in the key-value pair
116
   */
117
  @Immutable
118
  @SuppressWarnings("UnusedTypeParameter")
119
  public static final class Key<T> {
120
    private final String debugString;
121

122
    private Key(String debugString) {
1 ✔
123
      this.debugString = debugString;
1 ✔
124
    }
1 ✔
125

126
    @Override
127
    public String toString() {
128
      return debugString;
1 ✔
129
    }
130

131
    /**
132
     * Factory method for creating instances of {@link Key}.
133
     *
134
     * @param debugString a string used to describe the key, used for debugging.
135
     * @param <T> Key type
136
     * @return Key object
137
     * @deprecated use {@link #create} instead. This method will be removed in the future.
138
     */
139
    @Deprecated
140
    public static <T> Key<T> of(String debugString) {
141
      return new Key<>(debugString);
×
142
    }
143

144
    /**
145
     * Factory method for creating instances of {@link Key}.
146
     *
147
     * @param debugString a string used to describe the key, used for debugging.
148
     * @param <T> Key type
149
     * @return Key object
150
     */
151
    public static <T> Key<T> create(String debugString) {
152
      return new Key<>(debugString);
1 ✔
153
    }
154
  }
155

156
  @Override
157
  public String toString() {
158
    return data.toString();
1 ✔
159
  }
160

161
  /**
162
   * Returns true if the given object is also a {@link Attributes} with an equal attribute values.
163
   *
164
   * <p>Note that if a stored values are mutable, it is possible for two objects to be considered
165
   * equal at one point in time and not equal at another (due to concurrent mutation of attribute
166
   * values).
167
   *
168
   * <p>This method is not implemented efficiently and is meant for testing.
169
   *
170
   * @param o an object.
171
   * @return true if the given object is a {@link Attributes} equal attributes.
172
   */
173
  @Override
174
  public boolean equals(Object o) {
175
    if (this == o) {
1 ✔
176
      return true;
1 ✔
177
    }
178
    if (o == null || getClass() != o.getClass()) {
1 ✔
179
      return false;
×
180
    }
181
    Attributes that = (Attributes) o;
1 ✔
182
    if (data.size() != that.data.size()) {
1 ✔
183
      return false;
1 ✔
184
    }
185
    for (Map.Entry<Key<?>, Object> e : data.entrySet()) {
1 ✔
186
      if (!that.data.containsKey(e.getKey())) {
1 ✔
187
        return false;
×
188
      }
189
      if (!Objects.equal(e.getValue(), that.data.get(e.getKey()))) {
1 ✔
190
        return false;
×
191
      }
192
    }
1 ✔
193
    return true;
1 ✔
194
  }
195

196
  /**
197
   * Returns a hash code for the attributes.
198
   *
199
   * <p>Note that if a stored values are mutable, it is possible for two objects to be considered
200
   * equal at one point in time and not equal at another (due to concurrent mutation of attribute
201
   * values).
202
   *
203
   * @return a hash code for the attributes map.
204
   */
205
  @Override
206
  public int hashCode() {
207
    int hashCode = 0;
1 ✔
208
    for (Map.Entry<Key<?>, Object> e : data.entrySet()) {
1 ✔
209
      hashCode += Objects.hashCode(e.getKey(), e.getValue());
1 ✔
210
    }
1 ✔
211
    return hashCode;
1 ✔
212
  }
213

214
  /**
215
   * The helper class to build an Attributes instance.
216
   */
217
  public static final class Builder {
1 ✔
218
    // Exactly one of base and newdata will be set
219
    private Attributes base;
220
    private IdentityHashMap<Key<?>, Object> newdata;
221

222
    private Builder(Attributes base) {
1 ✔
223
      assert base != null;
1 ✔
224
      this.base = base;
1 ✔
225
    }
1 ✔
226

227
    private IdentityHashMap<Key<?>, Object> data(int size) {
228
      if (newdata == null) {
1 ✔
229
        newdata = new IdentityHashMap<>(base.data.size() + size);
1 ✔
230
        newdata.putAll(base.data);
1 ✔
231
        base = null;
1 ✔
232
      }
233
      assert base == null;
1 ✔
234
      return newdata;
1 ✔
235
    }
236

237
    public <T> Builder set(Key<T> key, T value) {
238
      data(1).put(key, value);
1 ✔
239
      return this;
1 ✔
240
    }
241

242
    /**
243
     * Removes the key and associated value from the attributes.
244
     *
245
     * @since 1.22.0
246
     * @param key The key to remove
247
     * @return this
248
     */
249
    public <T> Builder discard(Key<T> key) {
250
      if (base != null) {
1 ✔
251
        if (base.data.containsKey(key)) {
1 ✔
252
          data(0).remove(key);
1 ✔
253
        }
254
      } else {
255
        newdata.remove(key);
1 ✔
256
      }
257
      return this;
1 ✔
258
    }
259

260
    public Builder setAll(Attributes other) {
261
      data(other.data.size()).putAll(other.data);
1 ✔
262
      return this;
1 ✔
263
    }
264

265
    /**
266
     * Build the attributes.
267
     */
268
    public Attributes build() {
269
      if (newdata != null) {
1 ✔
270
        base = new Attributes(newdata);
1 ✔
271
        newdata = null;
1 ✔
272
      }
273
      return base;
1 ✔
274
    }
275
  }
276
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc