@Test public void waitForInitialRemoteData_readOnlyTrue_throwsIfWrongServerSchema() { SyncCredentials credentials = SyncCredentials.usernamePassword(UUID.randomUUID().toString(), "password", true); SyncUser user = SyncUser.login(credentials, Constants.AUTH_URL); final SyncConfiguration configNew = configurationFactory.createSyncConfigurationBuilder(user, Constants.USER_REALM) .waitForInitialRemoteData() .readOnly() .schema(StringOnly.class) .build(); assertFalse(configNew.realmExists()); Realm realm = null; try { // This will fail, because the server Realm is completely empty and the Client is not allowed to write the // schema. realm = Realm.getInstance(configNew); fail(); } catch (RealmMigrationNeededException ignored) { } finally { if (realm != null) { realm.close(); } user.logout(); } }
/** * The constructor is private to enforce the use of the static one. * * @param cache the {@link RealmCache} associated to this Realm instance. * @throws IllegalArgumentException if trying to open an encrypted Realm with the wrong key. */ private Realm(RealmCache cache) { super(cache, createExpectedSchemaInfo(cache.getConfiguration().getSchemaMediator())); schema = new ImmutableRealmSchema(this, new ColumnIndices(configuration.getSchemaMediator(), sharedRealm.getSchemaInfo())); // FIXME: This is to work around the different behaviour between the read only Realms in the Object Store and // in current java implementation. Opening a read only Realm with some missing schemas is allowed by Object // Store and realm-cocoa. In that case, any query based on the missing schema should just return an empty // results. Fix this together with https://github.com/realm/realm-java/issues/2953 if (configuration.isReadOnly()) { RealmProxyMediator mediator = configuration.getSchemaMediator(); Set<Class<? extends RealmModel>> classes = mediator.getModelClasses(); for (Class<? extends RealmModel> clazz : classes) { String tableName = Table.getTableNameForClass(mediator.getSimpleClassName(clazz)); if (!sharedRealm.hasTable(tableName)) { sharedRealm.close(); throw new RealmMigrationNeededException(configuration.getPath(), String.format(Locale.US, "Cannot open the read only Realm. '%s' is missing.", Table.getClassNameForTable(tableName))); } } } }
@Test public void getInstance_realmClosedAfterMigrationException() throws IOException { String REALM_NAME = "default0.realm"; RealmConfiguration realmConfig = configFactory.createConfiguration(REALM_NAME); configFactory.copyRealmFromAssets(context, REALM_NAME, REALM_NAME); try { Realm.getInstance(realmConfig); fail("A migration should be triggered"); } catch (RealmMigrationNeededException expected) { Realm.deleteRealm(realmConfig); // Deletes old realm. } // This should recreate the Realm with proper schema. Realm realm = Realm.getInstance(realmConfig); int result = realm.where(AllTypes.class).equalTo("columnString", "Foo").findAll().size(); assertEquals(0, result); realm.close(); }
@Test public void migrationException_realmListChanged() throws IOException { RealmConfiguration config = configFactory.createConfiguration(); // Initialize the schema with RealmList<Cat> Realm.getInstance(configFactory.createConfiguration()).close(); DynamicRealm dynamicRealm = DynamicRealm.getInstance(config); dynamicRealm.beginTransaction(); // Change the RealmList type to RealmList<Dog> RealmObjectSchema dogSchema = dynamicRealm.getSchema().get(Dog.CLASS_NAME); RealmObjectSchema ownerSchema = dynamicRealm.getSchema().get(CatOwner.CLASS_NAME); ownerSchema.removeField(CatOwner.FIELD_CATS); ownerSchema.addRealmListField(CatOwner.FIELD_CATS, dogSchema); dynamicRealm.commitTransaction(); dynamicRealm.close(); try { realm = Realm.getInstance(config); fail(); } catch (RealmMigrationNeededException ignored) { assertThat(ignored.getMessage(), CoreMatchers.containsString("Property 'CatOwner.cats' has been changed from 'array<Dog>' to 'array<Cat>'")); } }
@Test public void migrating_nullableField_toward_notNullable_PrimaryKeyThrows() throws IOException { configFactory.copyRealmFromAssets(context, "default-nullable-primarykey.realm", Realm.DEFAULT_REALM_NAME); final Class[] classes = {PrimaryKeyAsByte.class, PrimaryKeyAsShort.class, PrimaryKeyAsInteger.class, PrimaryKeyAsLong.class}; for (final Class clazz : classes) { try { RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() .schema(clazz) .build(); Realm realm = Realm.getInstance(realmConfig); realm.close(); fail(); } catch (RealmMigrationNeededException expected) { assertThat(expected.getMessage(), CoreMatchers.containsString( String.format("Property '%s.%s' has been made required", clazz.getSimpleName(), "id"))); } } }
@Test public void migrationRequired_throwsOriginalException() { RealmConfiguration config = configFactory.createConfigurationBuilder() // .migration() No migration block provided, but one is required .assetFile("default0.realm") // This Realm does not have the correct schema .build(); Realm realm = null; try { realm = Realm.getInstance(config); fail(); } catch (RealmMigrationNeededException ignored) { } finally { if (realm != null) { realm.close(); } } }
@Test public void getInstance_wrongSchemaInReadonlyThrows() { RealmConfiguration config = configFactory.createConfigurationBuilder() .name("readonly.realm") .schema(StringOnlyReadOnly.class, AllJavaTypes.class) .assetFile("readonly.realm") .readOnly() .build(); // This will throw because the Realm doesn't have the correct schema, and a new file cannot be re-created // because it is read only. try { realm = Realm.getInstance(config); fail(); } catch (RealmMigrationNeededException ignored) { } }
@Test public void constructBuilder_versionEqualWhenSchemaChangesThrows() { // Creates initial Realm. RealmConfiguration config = new RealmConfiguration.Builder(context) .directory(configFactory.getRoot()) .schemaVersion(42) .schema(StringOnly.class) .build(); Realm.getInstance(config).close(); // Creates new instance with a configuration containing another schema. try { config = new RealmConfiguration.Builder(context) .directory(configFactory.getRoot()) .schemaVersion(42) .schema(StringAndInt.class) .build(); realm = Realm.getInstance(config); fail("A migration should be required"); } catch (RealmMigrationNeededException ignored) { } }
private void setupMetadataRealm() { final int METADATA_DB_SCHEMA_VERSION = 4; Realm.init(this); RealmConfiguration config = new RealmConfiguration.Builder() .modules(new BlogMetadataModule()) .schemaVersion(METADATA_DB_SCHEMA_VERSION) .migration(new BlogMetadataDBMigration()) .build(); Realm.setDefaultConfiguration(config); // open the Realm to check if a migration is needed try { Realm realm = Realm.getDefaultInstance(); realm.close(); } catch (RealmMigrationNeededException e) { // delete existing Realm if we're below v4 if (mHACKOldSchemaVersion >= 0 && mHACKOldSchemaVersion < 4) { Realm.deleteRealm(config); mHACKOldSchemaVersion = -1; } } AnalyticsService.logMetadataDbSchemaVersion(String.valueOf(METADATA_DB_SCHEMA_VERSION)); }
public static void setupRealm(Context context) { // Setup RealmConfiguration realmConfig = getRealmConfiguration(context); Realm.setDefaultConfiguration(realmConfig); try { Realm realm = Realm.getDefaultInstance(); realm.close(); } catch (RealmMigrationNeededException exception) { Log.d(TAG, "New version! Destroy everything"); Realm.deleteRealm(realmConfig); } }
@Test public void migrationException_getPath() throws IOException { configFactory.copyRealmFromAssets(context, "default0.realm", Realm.DEFAULT_REALM_NAME); File realm = new File(configFactory.getRoot(), Realm.DEFAULT_REALM_NAME); try { Realm.getInstance(configFactory.createConfiguration()); fail(); } catch (RealmMigrationNeededException expected) { assertEquals(expected.getPath(), realm.getCanonicalPath()); } }
/** * Table validation should fail if the backlinked column already exists in the target table. * The realm `backlinks-fieldInUse.realm` contains the classes `BacklinksSource` and `BacklinksTarget` * except that in the definition of {@code BacklinksTarget}, the field parent is defined as: * <pre> * {@code * private RealmList<BacklinksSource> parents; * } * </pre> * * <p/> * The backlinked field does exist but it is list of links to {@code BacklinksSource} children * not a list of backlinks to {@code BacklinksSource} parents of which the {@code BacklinksTarget} * is a child. */ @Test public void migration_backlinkedFieldInUse() { final String realmName = "backlinks-fieldInUse.realm"; RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() .name(realmName) .schema(BacklinksSource.class, BacklinksTarget.class) .build(); try { configFactory.copyRealmFromAssets(context, realmName, realmName); Realm localRealm = Realm.getInstance(realmConfig); localRealm.close(); fail("A migration should have been required"); } catch (IOException e) { fail("Failed copying realm"); } catch (RealmMigrationNeededException expected) { assertThat(expected.getMessage(), CoreMatchers.allOf( CoreMatchers.containsString("Property 'BacklinksSource.name' has been added"), CoreMatchers.containsString("Property 'BacklinksTarget.parents' has been removed"))); } finally { Realm.deleteRealm(realmConfig); } }
@SuppressLint("DefaultLocale") @Override public void migrate(@NonNull DynamicRealm realm, long oldVersion, long newVersion) { if (oldVersion < newVersion) { // Unknown migration throw new RealmMigrationNeededException(realm.getPath(), String.format("Migration missing from v%d to v%d", oldVersion, newVersion)); } }
public RealmHelper(Application application) { RealmConfiguration configuration = new RealmConfiguration.Builder(application).deleteRealmIfMigrationNeeded().build(); try { Realm.setDefaultConfiguration(configuration); realmDB = Realm.getDefaultInstance(); } catch (RealmMigrationNeededException e) { Realm.deleteRealm(configuration); realmDB = Realm.getDefaultInstance(); } }
public GreenHubDb() { try { mRealm = Realm.getDefaultInstance(); } catch (RealmMigrationNeededException e) { // handle migration exception io.realm.exceptions.RealmMigrationNeededException e.printStackTrace(); } }
@Override public void onCreate() { super.onCreate(); instance = this; try { Realm.getInstance(this); } catch (RealmMigrationNeededException expected) { Realm.deleteRealmFile(this); // Delete old realm } }
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setHasOptionsMenu(true); Log.i(TAG, "onCreate()"); mActivity = (ActionBarActivity) getActivity(); try { mRealm = Realm.getInstance(mActivity); } catch (RealmMigrationNeededException e) { e.printStackTrace(); Realm.deleteRealmFile(mActivity); } mRealmHelper = new RealmHelper(); }
/** * Migrates the Realm file defined by the given configuration using the provided migration block. * * @param configuration configuration for the Realm that should be migrated. If this is a SyncConfiguration this * method does nothing. * @param migration if set, this migration block will override what is set in {@link RealmConfiguration}. * @throws FileNotFoundException if the Realm file doesn't exist. * @throws IllegalArgumentException if the provided configuration is a {@code SyncConfiguration}. */ protected static void migrateRealm(final RealmConfiguration configuration, @Nullable final RealmMigration migration) throws FileNotFoundException { //noinspection ConstantConditions if (configuration == null) { throw new IllegalArgumentException("RealmConfiguration must be provided"); } if (configuration.isSyncConfiguration()) { throw new IllegalArgumentException("Manual migrations are not supported for synced Realms"); } if (migration == null && configuration.getMigration() == null) { throw new RealmMigrationNeededException(configuration.getPath(), "RealmMigration must be provided."); } final AtomicBoolean fileNotFound = new AtomicBoolean(false); RealmCache.invokeWithGlobalRefCount(configuration, new RealmCache.Callback() { @Override public void onResult(int count) { if (count != 0) { throw new IllegalStateException("Cannot migrate a Realm file that is already open: " + configuration.getPath()); } File realmFile = new File(configuration.getPath()); if (!realmFile.exists()) { fileNotFound.set(true); return; } RealmProxyMediator mediator = configuration.getSchemaMediator(); OsSchemaInfo schemaInfo = new OsSchemaInfo(mediator.getExpectedObjectSchemaInfoMap().values()); OsSharedRealm.MigrationCallback migrationCallback = null; final RealmMigration migrationToBeApplied = migration != null ? migration : configuration.getMigration(); if (migrationToBeApplied != null) { migrationCallback = createMigrationCallback(migrationToBeApplied); } OsRealmConfig.Builder configBuilder = new OsRealmConfig.Builder(configuration) .autoUpdateNotification(false) .schemaInfo(schemaInfo) .migrationCallback(migrationCallback); OsSharedRealm sharedRealm = null; try { sharedRealm = OsSharedRealm.getInstance(configBuilder); } finally { if (sharedRealm != null) { sharedRealm.close(); } } } }); if (fileNotFound.get()) { throw new FileNotFoundException("Cannot migrate a Realm file which doesn't exist: " + configuration.getPath()); } }
@Test public void notSettingRequiredForNotNullableThrows() { String[] notNullableFields = {NullTypes.FIELD_STRING_NOT_NULL, NullTypes.FIELD_BYTES_NOT_NULL, NullTypes.FIELD_BOOLEAN_NOT_NULL, NullTypes.FIELD_BYTE_NOT_NULL, NullTypes.FIELD_SHORT_NOT_NULL, NullTypes.FIELD_INTEGER_NOT_NULL, NullTypes.FIELD_LONG_NOT_NULL, NullTypes.FIELD_FLOAT_NOT_NULL, NullTypes.FIELD_DOUBLE_NOT_NULL, NullTypes.FIELD_DATE_NOT_NULL}; for (final String field : notNullableFields) { final RealmMigration migration = new RealmMigration() { @Override public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { if (oldVersion == 0) { // 0 after initNullTypesTableExcludes // No @Required for not nullable field RealmObjectSchema nullTypesSchema = realm.getSchema().get(NullTypes.CLASS_NAME); if (field.equals(NullTypes.FIELD_STRING_NOT_NULL)) { // 1 String nullTypesSchema.addField(field, String.class); } else if (field.equals(NullTypes.FIELD_BYTES_NOT_NULL)) { // 2 Bytes nullTypesSchema.addField(field, byte[].class); } else if (field.equals(NullTypes.FIELD_BOOLEAN_NOT_NULL)) { // 3 Boolean nullTypesSchema.addField(field, Boolean.class); //table.addColumn(RealmFieldType.BOOLEAN, field, Table.NULLABLE); } else if (field.equals(NullTypes.FIELD_BYTE_NOT_NULL) || field.equals(NullTypes.FIELD_SHORT_NOT_NULL) || field.equals(NullTypes.FIELD_INTEGER_NOT_NULL) || field.equals(NullTypes.FIELD_LONG_NOT_NULL)) { // 4 Byte 5 Short 6 Integer 7 Long nullTypesSchema.addField(field, Integer.class); } else if (field.equals(NullTypes.FIELD_FLOAT_NOT_NULL)) { // 8 Float nullTypesSchema.addField(field, Float.class); } else if (field.equals(NullTypes.FIELD_DOUBLE_NOT_NULL)) { // 9 Double nullTypesSchema.addField(field, Double.class); } else if (field.equals(NullTypes.FIELD_DATE_NOT_NULL)) { // 10 Date nullTypesSchema.addField(field, Date.class); } // 11 Object skipped } } }; @SuppressWarnings("unchecked") RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() .schemaVersion(1) .name(field) .schema(NullTypes.class) .migration(migration) .build(); Realm.deleteRealm(realmConfig); // Prepares the version 0 db. DynamicRealm dynamicRealm = DynamicRealm.getInstance(realmConfig); TestHelper.initNullTypesTableExcludes(dynamicRealm, field); dynamicRealm.close(); try { realm = Realm.getInstance(realmConfig); fail("Failed on " + field); } catch (RealmMigrationNeededException e) { assertThat(e.getMessage(), CoreMatchers.containsString( String.format(Locale.US, "Property 'NullTypes.%s' has been made required", field))); } } }
@Test public void settingRequiredForNullableThrows() { String[] notNullableFields = {NullTypes.FIELD_STRING_NULL, NullTypes.FIELD_BYTES_NULL, NullTypes.FIELD_BOOLEAN_NULL, NullTypes.FIELD_BYTE_NULL, NullTypes.FIELD_SHORT_NULL, NullTypes.FIELD_INTEGER_NULL, NullTypes.FIELD_LONG_NULL, NullTypes.FIELD_FLOAT_NULL, NullTypes.FIELD_DOUBLE_NULL, NullTypes.FIELD_DATE_NULL}; for (final String field : notNullableFields) { final RealmMigration migration = new RealmMigration() { @Override public void migrate(DynamicRealm realm, long oldVersion, long newVersion) { if (oldVersion == 0) { // 0 after initNullTypesTableExcludes // No @Required for not nullable field RealmObjectSchema nullTypesSchema = realm.getSchema().get(NullTypes.CLASS_NAME); if (field.equals(NullTypes.FIELD_STRING_NULL)) { // 1 String nullTypesSchema.addField(field, String.class, FieldAttribute.REQUIRED); } else if (field.equals(NullTypes.FIELD_BYTES_NULL)) { // 2 Bytes nullTypesSchema.addField(field, byte[].class, FieldAttribute.REQUIRED); } else if (field.equals(NullTypes.FIELD_BOOLEAN_NULL)) { // 3 Boolean nullTypesSchema.addField(field, boolean.class); } else if (field.equals(NullTypes.FIELD_BYTE_NULL) || field.equals(NullTypes.FIELD_SHORT_NULL) || field.equals(NullTypes.FIELD_INTEGER_NULL) || field.equals(NullTypes.FIELD_LONG_NULL)) { // 4 Byte 5 Short 6 Integer 7 Long nullTypesSchema.addField(field, int.class); } else if (field.equals(NullTypes.FIELD_FLOAT_NULL)) { // 8 Float nullTypesSchema.addField(field, float.class); } else if (field.equals(NullTypes.FIELD_DOUBLE_NULL)) { // 9 Double nullTypesSchema.addField(field, double.class); } else if (field.equals(NullTypes.FIELD_DATE_NULL)) { // 10 Date nullTypesSchema.addField(field, Date.class, FieldAttribute.REQUIRED); } // 11 Object skipped } } }; @SuppressWarnings("unchecked") RealmConfiguration realmConfig = configFactory.createConfigurationBuilder() .schemaVersion(1) .name(field) .schema(NullTypes.class) .migration(migration) .build(); Realm.deleteRealm(realmConfig); // Prepares the version 0 db. DynamicRealm dynamicRealm = DynamicRealm.getInstance(realmConfig); TestHelper.initNullTypesTableExcludes(dynamicRealm, field); dynamicRealm.close(); try { realm = Realm.getInstance(realmConfig); fail("Failed on " + field); } catch (RealmMigrationNeededException e) { assertThat(e.getMessage(), CoreMatchers.containsString( String.format(Locale.US, "Property 'NullTypes.%s' has been made optional", field))); } } }