com.google.firebase.database.DataSnapshot Maven / Gradle / Ivy
/*
* Copyright 2017 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.firebase.database;
import com.google.firebase.database.annotations.Nullable;
import com.google.firebase.database.core.Path;
import com.google.firebase.database.snapshot.IndexedNode;
import com.google.firebase.database.snapshot.NamedNode;
import com.google.firebase.database.snapshot.Node;
import com.google.firebase.database.utilities.Validation;
import com.google.firebase.database.utilities.encoding.CustomClassMapper;
import java.util.Iterator;
/**
* A DataSnapshot instance contains data from a Firebase Database location. Any time you read
* Database data, you receive the data as a DataSnapshot.
*
* DataSnapshots are passed to the methods in listeners that you attach with {@link
* DatabaseReference#addValueEventListener(ValueEventListener)}, {@link
* DatabaseReference#addChildEventListener(ChildEventListener)}, or {@link
* DatabaseReference#addListenerForSingleValueEvent(ValueEventListener)}.
*
* They are efficiently-generated immutable copies of the data at a Firebase Database location. They
* can't be modified and will never change. To modify data at a location, use a {@link
* DatabaseReference DatabaseReference} reference (e.g. with {@link
* DatabaseReference#setValueAsync(Object)}).
*/
public class DataSnapshot {
private final IndexedNode node;
private final DatabaseReference query;
/**
* @param ref A DatabaseReference
* @param node The indexed node
*/
DataSnapshot(DatabaseReference ref, IndexedNode node) {
this.node = node;
this.query = ref;
}
/**
* Get a DataSnapshot for the location at the specified relative path. The relative path can
* either be a simple child key (e.g. 'fred') or a deeper slash-separated path (e.g.
* 'fred/name/first'). If the child location has no data, an empty DataSnapshot is returned.
*
* @param path A relative path to the location of child data
* @return The DataSnapshot for the child location
*/
public DataSnapshot child(String path) {
DatabaseReference childRef = query.child(path);
Node childNode = this.node.getNode().getChild(new Path(path));
return new DataSnapshot(childRef, IndexedNode.from(childNode));
}
/**
* Can be used to determine if this DataSnapshot has data at a particular location
*
* @param path A relative path to the location of child data
* @return Whether or not the specified child location has data
*/
public boolean hasChild(String path) {
if (query.getParent() == null) {
Validation.validateRootPathString(path);
} else {
Validation.validatePathString(path);
}
return !node.getNode().getChild(new Path(path)).isEmpty();
}
/**
* Indicates whether this snapshot has any children
*
* @return True if the snapshot has any children, otherwise false
*/
public boolean hasChildren() {
return node.getNode().getChildCount() > 0;
}
/**
* Returns true if the snapshot contains a non-null value.
*
* @return True if the snapshot contains a non-null value, otherwise false
*/
public boolean exists() {
return !node.getNode().isEmpty();
}
/**
* getValue() returns the data contained in this snapshot as native types. The possible types
* returned are:
*
*
* - Boolean
*
- String
*
- Long
*
- Double
*
- Map<String, Object>
*
- List<Object>
*
*
* This list is recursive; the possible types for Object
in the above list
* is given by the same list. These types correspond to the types available in JSON.
*
* @return The data contained in this snapshot as native types or null if there is no data at this
* location.
*/
@Nullable
public Object getValue() {
return node.getNode().getValue();
}
/**
* getValue() returns the data contained in this snapshot as native types. The possible types
* returned are:
*
*
* - Boolean
*
- String
*
- Long
*
- Double
*
- Map<String, Object>
*
- List<Object>
*
*
* This list is recursive; the possible types for Object
in the above list is
* given by the same list. These types correspond to the types available in JSON.
*
*
If useExportFormat is set to true, priority information will be included in the output.
* Priority information shows up as a .priority key in a map. For data that would not otherwise be
* a map, the map will also include a .value key with the data.
*
* @param useExportFormat Whether or not to include priority information
* @return The data, along with its priority, in native types or null if there is no data at this
* location.
*/
@Nullable
public Object getValue(boolean useExportFormat) {
return node.getNode().getValue(useExportFormat);
}
/**
* This method is used to marshall the data contained in this snapshot into a class of your
* choosing. The class must fit 2 simple constraints:
*
*
* - The class must have a default constructor that takes no arguments
*
- The class must define public getters for the properties to be assigned. Properties
* without a public getter will be set to their default value when an instance is
* deserialized
*
*
* An example class might look like:
*
*
* class Message {
* private String author;
* private String text;
*
* private Message() {}
*
* public Message(String author, String text) {
* this.author = author;
* this.text = text;
* }
*
* public String getAuthor() {
* return author;
* }
*
* public String getText() {
* return text;
* }
* }
*
*
* // Later
* Message m = snapshot.getValue(Message.class);
*
*
* @param valueType The class into which this snapshot should be marshalled
* @param The type to return. Implicitly defined from the class passed in
* @return An instance of the class passed in, populated with the data from this snapshot, or null
* if there is no data at this location.
*/
@Nullable
public T getValue(Class valueType) {
Object value = node.getNode().getValue();
return CustomClassMapper.convertToCustomClass(value, valueType);
}
/**
* Due to the way that Java implements generics, it takes an extra step to get back a
* properly-typed Collection. So, in the case where you want a List
of Message
* instances, you will need to do something like the following:
*
*
* GenericTypeIndicator<List<Message>> t = new GenericTypeIndicator<List<
* Message>>()
* {};
* List<Message> messages = snapshot.getValue(t);
*
*
* It is important to use a subclass of {@link GenericTypeIndicator}. See {@link
* GenericTypeIndicator} for more details
*
* @param t A subclass of {@link GenericTypeIndicator} indicating the type of generic collection
* to be returned.
* @param The type to return. Implicitly defined from the {@link GenericTypeIndicator} passed
* in
* @return A properly typed collection, populated with the data from this snapshot, or null if
* there is no data at this location.
*/
@Nullable
public T getValue(GenericTypeIndicator t) {
Object value = node.getNode().getValue();
return CustomClassMapper.convertToCustomClass(value, t);
}
/**
* @return The number of immediate children in the this snapshot
*/
public long getChildrenCount() {
return node.getNode().getChildCount();
}
/**
* Used to obtain a reference to the source location for this snapshot.
*
* @return A DatabaseReference corresponding to the location that this snapshot came from
*/
public DatabaseReference getRef() {
return query;
}
/**
* @return the key name for the source location of this snapshot
*/
public String getKey() {
return query.getKey();
}
/**
* Gives access to all of the immediate children of this snapshot. Can be used in native for
* loops:
*
for (DataSnapshot child : parent.getChildren()) {
*
...
*
}
*
*
* @return The immediate children of this snapshot
*/
public Iterable getChildren() {
final Iterator iter = node.iterator();
return new Iterable() {
@Override
public Iterator iterator() {
return new Iterator() {
@Override
public boolean hasNext() {
return iter.hasNext();
}
@Override
public DataSnapshot next() {
NamedNode namedNode = iter.next();
return new DataSnapshot(
query.child(namedNode.getName().asString()), IndexedNode.from(namedNode.getNode()));
}
@Override
public void remove() {
throw new UnsupportedOperationException("remove called on immutable collection");
}
};
}
};
}
/**
* Returns the priority of the data contained in this snapshot as a native type. Possible return
* types:
*
*
* - Double
*
- String
*
*
* Note that null is also allowed.
*
* @return the priority of the data contained in this snapshot as a native type
*/
public Object getPriority() {
Object priority = node.getNode().getPriority().getValue();
if (priority instanceof Long) {
return Double.valueOf((Long) priority);
} else {
return priority;
}
}
@Override
public String toString() {
return "DataSnapshot { key = "
+ this.query.getKey()
+ ", value = "
+ this.node.getNode().getValue(true)
+ " }";
}
}