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

grpc / grpc-java / #19102

14 Mar 2024 03:53AM UTC coverage: 88.259% (-0.05%) from 88.311%
#19102

push

github

web-flow
core: Eliminate NPE seen in PickFirstLeafLoadBalancer (#11013)

ref b/329420531

31150 of 35294 relevant lines covered (88.26%)

0.88 hits per line

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

89.39
/../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
    private Attributes base;
219
    private IdentityHashMap<Key<?>, Object> newdata;
220

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

226
    private IdentityHashMap<Key<?>, Object> data(int size) {
227
      if (newdata == null) {
1✔
228
        newdata = new IdentityHashMap<>(size);
1✔
229
      }
230
      return newdata;
1✔
231
    }
232

233
    public <T> Builder set(Key<T> key, T value) {
234
      data(1).put(key, value);
1✔
235
      return this;
1✔
236
    }
237

238
    /**
239
     * Removes the key and associated value from the attributes.
240
     *
241
     * @since 1.22.0
242
     * @param key The key to remove
243
     * @return this
244
     */
245
    public <T> Builder discard(Key<T> key) {
246
      if (base.data.containsKey(key)) {
1✔
247
        IdentityHashMap<Key<?>, Object> newBaseData = new IdentityHashMap<>(base.data);
1✔
248
        newBaseData.remove(key);
1✔
249
        base = new Attributes(newBaseData);
1✔
250
      }
251
      if (newdata != null) {
1✔
252
        newdata.remove(key);
1✔
253
      }
254
      return this;
1✔
255
    }
256

257
    public Builder setAll(Attributes other) {
258
      data(other.data.size()).putAll(other.data);
1✔
259
      return this;
1✔
260
    }
261

262
    /**
263
     * Build the attributes.
264
     */
265
    public Attributes build() {
266
      if (newdata != null) {
1✔
267
        for (Map.Entry<Key<?>, Object> entry : base.data.entrySet()) {
1✔
268
          if (!newdata.containsKey(entry.getKey())) {
1✔
269
            newdata.put(entry.getKey(), entry.getValue());
1✔
270
          }
271
        }
1✔
272
        base = new Attributes(newdata);
1✔
273
        newdata = null;
1✔
274
      }
275
      return base;
1✔
276
    }
277
  }
278
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc