private static Integer convertInteger(Object obj) { if (obj instanceof Integer) { return (Integer) obj; } else if (obj instanceof Long || obj instanceof Double) { double value = ((Number) obj).doubleValue(); if (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE) { return ((Number) obj).intValue(); } else { throw new DatabaseException( "Numeric value out of 32-bit integer range: " + value + ". Did you mean to use a long or double instead of an int?"); } } else { throw new DatabaseException( "Failed to convert a value of type " + obj.getClass().getName() + " to int"); } }
/** * Converts a standard library Java representation of JSON data to an object of the class provided * through the GenericTypeIndicator * * @param object The representation of the JSON data * @param typeIndicator The indicator providing class of the object to convert to * @return The POJO object. */ public static <T> T convertToCustomClass(Object object, GenericTypeIndicator<T> typeIndicator) { Class<?> clazz = typeIndicator.getClass(); Type genericTypeIndicatorType = clazz.getGenericSuperclass(); if (genericTypeIndicatorType instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) genericTypeIndicatorType; if (!parameterizedType.getRawType().equals(GenericTypeIndicator.class)) { throw new DatabaseException( "Not a direct subclass of GenericTypeIndicator: " + genericTypeIndicatorType); } // We are guaranteed to have exactly one type parameter Type type = parameterizedType.getActualTypeArguments()[0]; return deserializeToType(object, type); } else { throw new DatabaseException( "Not a direct subclass of GenericTypeIndicator: " + genericTypeIndicatorType); } }
@SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) private static <T> T deserializeToType(Object obj, Type type) { if (obj == null) { return null; } else if (type instanceof ParameterizedType) { return deserializeToParameterizedType(obj, (ParameterizedType) type); } else if (type instanceof Class) { return deserializeToClass(obj, (Class<T>) type); } else if (type instanceof WildcardType) { throw new DatabaseException("Generic wildcard types are not supported"); } else if (type instanceof GenericArrayType) { throw new DatabaseException( "Generic Arrays are not supported, please use Lists " + "instead"); } else { throw new IllegalStateException("Unknown type encountered: " + type); } }
@SuppressWarnings("unchecked") private static <T> T deserializeToPrimitive(Object obj, Class<T> clazz) { if (Integer.class.isAssignableFrom(clazz) || int.class.isAssignableFrom(clazz)) { return (T) convertInteger(obj); } else if (Boolean.class.isAssignableFrom(clazz) || boolean.class.isAssignableFrom(clazz)) { return (T) convertBoolean(obj); } else if (Double.class.isAssignableFrom(clazz) || double.class.isAssignableFrom(clazz)) { return (T) convertDouble(obj); } else if (Long.class.isAssignableFrom(clazz) || long.class.isAssignableFrom(clazz)) { return (T) convertLong(obj); } else if (Float.class.isAssignableFrom(clazz) || float.class.isAssignableFrom(clazz)) { return (T) (Float) convertDouble(obj).floatValue(); } else if (Short.class.isAssignableFrom(clazz) || short.class.isAssignableFrom(clazz)) { throw new DatabaseException("Deserializing to shorts is not supported"); } else if (Byte.class.isAssignableFrom(clazz) || byte.class.isAssignableFrom(clazz)) { throw new DatabaseException("Deserializing to bytes is not supported"); } else if (Character.class.isAssignableFrom(clazz) || char.class.isAssignableFrom(clazz)) { throw new DatabaseException("Deserializing to char is not supported"); } else { throw new IllegalArgumentException("Unknown primitive type: " + clazz); } }
@SuppressWarnings("unchecked") private static <T> T deserializeToEnum(Object object, Class<T> clazz) { if (object instanceof String) { String value = (String) object; // We cast to Class without generics here since we can't prove the bound // T extends Enum<T> statically try { return (T) Enum.valueOf((Class) clazz, value); } catch (IllegalArgumentException e) { throw new DatabaseException( "Could not find enum value of " + clazz.getName() + " for value \"" + value + "\""); } } else { throw new DatabaseException( "Expected a String while deserializing to enum " + clazz + " but got a " + object.getClass()); } }
private static Long convertLong(Object obj) { if (obj instanceof Integer) { return ((Integer) obj).longValue(); } else if (obj instanceof Long) { return (Long) obj; } else if (obj instanceof Double) { Double value = (Double) obj; if (value >= Long.MIN_VALUE && value <= Long.MAX_VALUE) { return value.longValue(); } else { throw new DatabaseException( "Numeric value out of 64-bit long range: " + value + ". Did you mean to use a double instead of a long?"); } } else { throw new DatabaseException( "Failed to convert a value of type " + obj.getClass().getName() + " to long"); } }
private void checkValid() throws DatabaseException { if (byteLength > MAX_PATH_LENGTH_BYTES) { throw new DatabaseException( "Data has a key path longer than " + MAX_PATH_LENGTH_BYTES + " bytes (" + byteLength + ")."); } if (parts.size() > MAX_PATH_DEPTH) { throw new DatabaseException( "Path specified exceeds the maximum depth that can be written (" + MAX_PATH_DEPTH + ") or object contains a cycle " + toErrorString()); } }
@Test public void testInvalidPathsToOrderBy() { DatabaseReference ref = IntegrationTestUtils.getRandomNode(masterApp); List<String> badKeys = ImmutableList.<String>builder() .add("$child/foo", "$childfoo", "$/foo", "$child/foo/bar", "$child/.foo", ".priority", "$priority", "$key", ".key", "$child/.priority") .build(); for (String key : badKeys) { try { ref.orderByChild(key); fail("Should throw"); } catch (DatabaseException | IllegalArgumentException e) { // ignore } } }
@Test public void testInvalidUpdate() { Map[] invalidUpdates = new Map[]{ ImmutableMap.of(".sv", "foo"), ImmutableMap.of(".value", "foo"), ImmutableMap.of(".priority", ImmutableMap.of("a", "b")), ImmutableMap.of("foo", "value", "foo/bar", "value"), ImmutableMap.of("foo", Double.POSITIVE_INFINITY), ImmutableMap.of("foo", Double.NEGATIVE_INFINITY), ImmutableMap.of("foo", Double.NaN), }; Path path = new Path("path"); for (Map map : invalidUpdates) { try { Validation.parseAndValidateUpdate(path, map); fail("No error thrown for invalid update: " + map); } catch (DatabaseException expected) { // expected } } }
@Override public void onDataChange(DataSnapshot dataSnapshot) { mFollowRequestArray.clear(); for(DataSnapshot snapshot : dataSnapshot.getChildren()) { FollowRequest request; try { request = snapshot.getValue(FollowRequest.class); } catch (DatabaseException e) { return; } if (onlyShowUnaccepted && request.getAccepted()) continue; if (onlyShowAccepted && !request.getAccepted()) continue; mFollowRequestArray.add(request); } datasetChanged(); }
public Boolean save(HighScore spacecraft) { if(spacecraft==null) { saved=false; }else { try { db.child("Spacecraft").push().setValue(spacecraft); saved=true; }catch (DatabaseException e) { e.printStackTrace(); saved=false; } } return saved; }
@Test public void testDataChanges_DataReference_onCancelled() { TestObserver<DataSnapshot> sub = TestObserver.create(); RxFirebaseDatabase.dataChanges(mockDatabaseReference) .subscribe(sub); verifyDataReferenceAddValueEventListener(); callValueEventOnCancelled(new DatabaseException("foo")); sub.assertError(DatabaseException.class); sub.assertNoValues(); sub.dispose(); callValueEventOnCancelled(new DatabaseException("foo")); // Ensure no more values are emitted after unsubscribe assertThat(sub.errorCount()) .isEqualTo(1); }
@Test public void testDataChanges_Query_onCancelled() { TestObserver<DataSnapshot> sub = TestObserver.create(); RxFirebaseDatabase.dataChanges(mockQuery) .subscribe(sub); verifyQueryAddValueEventListener(); callValueEventOnCancelled(new DatabaseException("foo")); sub.assertError(DatabaseException.class); sub.assertNoValues(); sub.dispose(); callValueEventOnCancelled(new DatabaseException("foo")); // Ensure no more values are emitted after unsubscribe assertThat(sub.errorCount()) .isEqualTo(1); }
@Test public void testRunTransaction_onError() { TestObserver sub = TestObserver.create(); RxFirebaseDatabase .runTransaction(mockDatabaseReference, mockTransactionTask) .subscribe(sub); verifyRunTransaction(); callTransactionOnCompleteWithError(new DatabaseException("Foo")); sub.assertNotComplete(); sub.assertError(DatabaseException.class); sub.dispose(); }
public static Node parsePriority(Path nodePath, Object value) { Node priority = NodeUtilities.NodeFromJSON(value); if (priority instanceof LongNode) { priority = new DoubleNode( Double.valueOf((Long) priority.getValue()), PriorityUtilities.NullPriority()); } if (!isValidPriority(priority)) { throw new DatabaseException( (nodePath != null ? "Path '" + nodePath + "'" : "Node") + " contains invalid priority: Must be a string, double, ServerValue, or null"); } return priority; }
public static void validatePathString(String pathString) throws DatabaseException { if (!isValidPathString(pathString)) { throw new DatabaseException( "Invalid Firebase Database path: " + pathString + ". Firebase Database paths must not contain '.', '#', '$', '[', or ']'"); } }
public static void validateRootPathString(String pathString) throws DatabaseException { if (pathString.startsWith(".info")) { validatePathString(pathString.substring(5)); } else if (pathString.startsWith("/.info")) { validatePathString(pathString.substring(6)); } else { validatePathString(pathString); } }
public static Map<Path, Node> parseAndValidateUpdate(Path path, Map<String, Object> update) throws DatabaseException { final SortedMap<Path, Node> parsedUpdate = new TreeMap<>(); for (Map.Entry<String, Object> entry : update.entrySet()) { Path updatePath = new Path(entry.getKey()); Object newValue = entry.getValue(); ValidationPath.validateWithObject(path.child(updatePath), newValue); String childName = !updatePath.isEmpty() ? updatePath.getBack().asString() : ""; if (childName.equals(ServerValues.NAME_SUBKEY_SERVERVALUE) || childName.equals("" + ".value")) { throw new DatabaseException( "Path '" + updatePath + "' contains disallowed child name: " + childName); } Node parsedValue; if (childName.equals(".priority")) { parsedValue = PriorityUtilities.parsePriority(updatePath, newValue); } else { parsedValue = NodeUtilities.NodeFromJSON(newValue); } Validation.validateWritableObject(newValue); parsedUpdate.put(updatePath, parsedValue); } // Check that update keys are not ancestors of each other. Path prevPath = null; for (Path curPath : parsedUpdate.keySet()) { // We rely on the property that sorting guarantees that ancestors come right before // descendants. hardAssert(prevPath == null || prevPath.compareTo(curPath) < 0); if (prevPath != null && prevPath.contains(curPath)) { throw new DatabaseException( "Path '" + prevPath + "' is an ancestor of '" + curPath + "' in an update."); } prevPath = curPath; } return parsedUpdate; }
@SuppressWarnings("unchecked") private static <T> T deserializeToClass(Object obj, Class<T> clazz) { if (obj == null) { return null; } else if (clazz.isPrimitive() || Number.class.isAssignableFrom(clazz) || Boolean.class.isAssignableFrom(clazz) || Character.class.isAssignableFrom(clazz)) { return deserializeToPrimitive(obj, clazz); } else if (String.class.isAssignableFrom(clazz)) { return (T) convertString(obj); } else if (clazz.isArray()) { throw new DatabaseException( "Converting to Arrays is not supported, please use Lists" + "instead"); } else if (clazz.getTypeParameters().length > 0) { throw new DatabaseException( "Class " + clazz.getName() + " has generic type " + "parameters, please use GenericTypeIndicator instead"); } else if (clazz.equals(Object.class)) { return (T) obj; } else if (clazz.isEnum()) { return deserializeToEnum(obj, clazz); } else { return convertBean(obj, clazz); } }
@SuppressWarnings("unchecked") private static Map<String, Object> expectMap(Object object) { if (object instanceof Map) { // TODO: runtime validation of keys? return (Map<String, Object>) object; } else { throw new DatabaseException( "Expected a Map while deserializing, but got a " + object.getClass()); } }
private static Boolean convertBoolean(Object obj) { if (obj instanceof Boolean) { return (Boolean) obj; } else { throw new DatabaseException( "Failed to convert value of type " + obj.getClass().getName() + " to boolean"); } }
private static String convertString(Object obj) { if (obj instanceof String) { return (String) obj; } else { throw new DatabaseException( "Failed to convert value of type " + obj.getClass().getName() + " to String"); } }
private static <T> T convertBean(Object obj, Class<T> clazz) { BeanMapper<T> mapper = loadOrCreateBeanMapperForClass(clazz); if (obj instanceof Map) { return mapper.deserialize(expectMap(obj)); } else { throw new DatabaseException( "Can't convert object of type " + obj.getClass().getName() + " to type " + clazz.getName()); } }
private void addProperty(String property) { String oldValue = this.properties.put(property.toLowerCase(), property); if (oldValue != null && !property.equals(oldValue)) { throw new DatabaseException( "Found two getters or fields with conflicting case " + "sensitivity for property: " + property.toLowerCase()); } }
private Repo getLocalRepo(Context ctx, RepoInfo info) throws DatabaseException { ctx.freeze(); // No-op if it's already frozen String repoHash = "https://" + info.host + "/" + info.namespace; synchronized (repos) { if (!repos.containsKey(ctx) || !repos.get(ctx).containsKey(repoHash)) { // Calling this should create the repo. InternalHelpers.createDatabaseForTests( FirebaseApp.getInstance(), info, (DatabaseConfig) ctx); } return repos.get(ctx).get(repoHash); } }
private ValidationPath(Path path) throws DatabaseException { for (ChildKey key : path) { parts.add(key.asString()); } // Initialize to number of '/' chars needed in path. byteLength = Math.max(1, parts.size()); for (int i = 0; i < parts.size(); i++) { byteLength += utf8Bytes(parts.get(i)); } checkValid(); }
private void push(String child) throws DatabaseException { // Count the '/' if (parts.size() > 0) { byteLength += 1; } parts.add(child); byteLength += utf8Bytes(child); checkValid(); }
public static Path getRelative(Path from, Path to) { ChildKey outerFront = from.getFront(); ChildKey innerFront = to.getFront(); if (outerFront == null) { return to; } else if (outerFront.equals(innerFront)) { return getRelative(from.popFront(), to.popFront()); } else { throw new DatabaseException("INTERNAL ERROR: " + to + " is not contained in " + from); } }
private void updateInfo(ChildKey childKey, Object value) { if (childKey.equals(Constants.DOT_INFO_SERVERTIME_OFFSET)) { serverClock.setOffset((Long) value); } Path path = new Path(Constants.DOT_INFO, childKey); try { Node node = NodeUtilities.NodeFromJSON(value); infoData.update(path, node); List<? extends Event> events = this.infoSyncTree.applyServerOverwrite(path, node); this.postEvents(events); } catch (DatabaseException e) { operationLogger.error("Failed to parse info update", e); } }
/** * By default Firebase Database will use up to 10MB of disk space to cache data. If the cache * grows beyond this size, Firebase Database will start removing data that hasn't been recently * used. If you find that your application caches too little or too much data, call this method to * change the cache size. This method must be called before creating your first Database reference * and only needs to be called once per application. * * <p>Note that the specified cache size is only an approximation and the size on disk may * temporarily exceed it at times. * * @param cacheSizeInBytes The new size of the cache in bytes. * @since 2.3 */ public synchronized void setPersistenceCacheSizeBytes(long cacheSizeInBytes) { assertUnfrozen(); if (cacheSizeInBytes < 1024 * 1024) { throw new DatabaseException("The minimum cache size must be at least 1MB"); } if (cacheSizeInBytes > 100 * 1024 * 1024) { throw new DatabaseException( "Firebase Database currently doesn't support a cache size larger than 100MB"); } this.cacheSize = cacheSizeInBytes; }
@Test public void testInfoNodeSetValue() { DatabaseReference ref = FirebaseDatabase.getInstance().getReference(".info"); try { ref.setValueAsync("hi"); fail("Should not be allowed"); } catch (DatabaseException expected) { // No-op, expected } }
@Test public void testInfoNodeSetValueWithPriority() { DatabaseReference ref = FirebaseDatabase.getInstance().getReference(".info"); try { ref.setValueAsync("hi", 5); fail("Should not be allowed"); } catch (DatabaseException expected) { // No-op, expected } }
@Test public void testInfoNodeSetPriority() { DatabaseReference ref = FirebaseDatabase.getInstance().getReference(".info"); try { ref.setPriorityAsync("hi"); fail("Should not be allowed"); } catch (DatabaseException expected) { // No-op, expected } }
@Test public void testInfoNodeRemoveValue() { DatabaseReference ref = FirebaseDatabase.getInstance().getReference(".info"); try { ref.removeValueAsync(); fail("Should not be allowed"); } catch (DatabaseException expected) { // No-op, expected } }
@Test public void testInfoNodeChildSetValue() { DatabaseReference ref = FirebaseDatabase.getInstance().getReference(".info"); try { ref.child("test").setValueAsync("hi"); fail("Should not be allowed"); } catch (DatabaseException expected) { // No-op, expected } }
@Test public void testNormalizeDifferentIntegerAndDoubleValues() throws DatabaseException, InterruptedException, TimeoutException, TestFailure { final long intMaxPlusOne = 2147483648L; DatabaseReference node = IntegrationTestUtils.getRandomNode(masterApp); Object[] writtenValues = { intMaxPlusOne, (double) intMaxPlusOne, -intMaxPlusOne, (double) -intMaxPlusOne, Integer.MAX_VALUE, 0L, 0.0, -0.0f, 0 }; Object[] readValues = {intMaxPlusOne, -intMaxPlusOne, (long) Integer.MAX_VALUE, 0L}; ReadFuture readFuture = ReadFuture.untilCountAfterNull(node, readValues.length); for (Object value : writtenValues) { node.setValueAsync(value); } List<EventRecord> events = readFuture.timedGet(); for (int i = 0; i < readValues.length; ++i) { assertEquals(readValues[i], events.get(i).getSnapshot().getValue()); } }
@Test public void testNameForRootAndNonRootLocations() throws DatabaseException { DatabaseReference ref = FirebaseDatabase.getInstance(masterApp).getReference(); assertNull(ref.getKey()); assertEquals("a", ref.child("a").getKey()); assertEquals("c", ref.child("b/c").getKey()); }
@Test public void testParentForRootAndNonRootLocations() throws DatabaseException { DatabaseReference ref = FirebaseDatabase.getInstance(masterApp).getReference(); assertNull(ref.getParent()); DatabaseReference child = ref.child("a"); assertEquals(ref, child.getParent()); child = ref.child("a/b/c"); assertEquals(ref, child.getParent().getParent().getParent()); }
@Test public void testRootForRootAndNonRootLocations() throws DatabaseException { DatabaseReference ref = IntegrationTestUtils.getRandomNode(masterApp); ref = ref.getRoot(); assertEquals(IntegrationTestUtils.getDatabaseUrl(), ref.toString()); ref = ref.getRoot(); // Should be a no-op assertEquals(IntegrationTestUtils.getDatabaseUrl(), ref.toString()); }