/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.ipc.invalidation.ticl;
import com.google.common.base.Preconditions;
import com.google.protobuf.AbstractMessageLite;
import java.util.Arrays;
/**
* Wraps a Lite protobuf type and provides appropriate {@link #equals} and {@link #hashCode}
* implementations so the wrapped object can be stored in a Java collection and/or compared to other
* wrapped proto instances of the same type for equality. This is necessary because protobuf classes
* generated with the {@code LITE_RUNTIME} optimization do not have custom implementations of these
* methods (so only support simple object equivalence).
*
* @param <P> the protobuf message lite type that is being wrapped.
*/
public class ProtoWrapper<P extends AbstractMessageLite> {
/** The wrapped proto object */
private final P proto;
/** The serialized byte representation of the wrapped object */
private final byte [] protoBytes;
/** The hash code of the serialized representation */
private final int hashCode;
/** Returns a ProtoWrapper that wraps the provided object */
public static <M extends AbstractMessageLite> ProtoWrapper<M> of(M proto) {
return new ProtoWrapper<M>(proto);
}
// Internal constructor that savees the object and computes serialized state and hash code.
private ProtoWrapper(P proto) {
this.proto = Preconditions.checkNotNull(proto);
this.protoBytes = proto.toByteArray();
this.hashCode = Arrays.hashCode(protoBytes);
}
/** Returns the wrapped proto object */
public P getProto() {
return proto;
}
/** Returns the hash code of the serialized state representation of the protobuf object */
@Override
public int hashCode() {
return hashCode;
}
/**
* Returns {@code true} if the provided object is a proto wrapper of an object of the same
* protobuf type that has the same serialized state representation.
*/
@Override
public boolean equals(Object o) {
Class<?> msgClass = proto.getClass();
if (!(o instanceof ProtoWrapper)) {
return false;
}
@SuppressWarnings("rawtypes")
ProtoWrapper<?> wrapper = (ProtoWrapper) o;
if (proto.getClass() != wrapper.proto.getClass()) {
return false;
}
if (hashCode != wrapper.hashCode) {
return false;
}
return Arrays.equals(protoBytes, wrapper.protoBytes);
}
@Override
public String toString() {
// Don't print exactly the protocol buffer because that could be extremely confusing when
// debugging, since this object isn't actually a protocol buffer.
return "PW-" + proto.toString();
}
}