I'm using Realm, a framework used for creating persistent objects on mobile devices. Realm does not support nested transactions. So the problem is: I have a class with a static block that executes a Realm transaction, however, the first time the class is used in my code is by one of its static methods from within another Realm transaction. The error I'm getting is a java.lang.ExceptionInInitializerError, and it is caused by this:
Caused by: java.lang.IllegalStateException: Nested transactions are not allowed. Use commitTransaction() after each beginTransaction().
And the line of code that it brings me to that's causing the error is the line in the static block that is executing the transaction.
Because the first time the class is used is in a Realm transaction, it seems like the static block is not executed until that point, which is why I get the error caused by the nested transactions.
So just to clarify, it doesn't matter what type of variables a class has: static, static final, or whether they're initialized as instance variables or in a static block. Those variables will not be initialized until the class is interacted with for the first time. Correct?
Update:
Here is the code that occurred in the static block:
RealmSingleton.getUserInstance().executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
users.deleteAllFromRealm();
}
});
Related
I have a singleton class 'RealmDatabaseManager' where i have synchronized methods for reading/writing from realm local database.
The methods look like this:
public long getPendingImagesCount() {
synchronized (this) {
realm = Realm.getInstance(RealmUtils.getRealmConfiguration());
long count = realm.where(PatientRecordImage.class)
.count();
realm.close();
return count;
}
}
Where this is the instance of singleton class.
These methods are accessed from main as well as worker threads via the singleton instance. Every method creates and closes it's own realm.
The code works without issues on the devices i'm testing on but I've received Crashlytics reports from some devices giving two fatal errors.
IllegalStateException: Realm objects can only be accessed on the thread they were created.
And
IllegalStateException: Realm instance can only be closed on the thread it was created.
What is wrong with this approach? Can provide more info if needed.
Probably because you're setting the class variable to another Realm, and you have some fairly intricate multi-threading problem going on; nothing to do with device-specificness.
Solution: don't set the class level variable?
public long getPendingImagesCount() {
try(Realm realm = Realm.getInstance(RealmUtils.getRealmConfiguration())) {
return realm.where(PatientRecordImage.class).count();
}
}
i came across something interesting while running some unit tests. i have the following method:
private void createSchemaIfNecessary() throws SQLException, IOException{
if(!schemaExists){
try (Connection connection = dataSource.getConnection(); Statement statement = connection.createStatement();) {
statement.execute(getSQLByFileName(GOLF_COURSE_TABLE_CREATION_SCRIPT));
statement.execute(getSQLByFileName(GOLF_COURSE_HOLE_TABLE_CREATION_SCRIPT));
connection.commit();
schemaExists = true;
}
}
}
each unit test calls this method to determine whether or not to create the tables. the schemaExists variable is a member variable. i noticed that as each test was running, there were cases where even after hitting the schemaExists = true; line, the next time the method was called, schemaExists evaluated to false. i then made the variable static, and that fixed the problem.
As the individual unit tests are running, don't they all run within the context of a single instance of the unit test class?
I'm going to assume schemaExists is a non-static member of your test class.
Before invoking a test method (annotated #Test), junit (by default) creates a new instance of your test class (More detail here).
Thus, any non-static class member will be initialized as per defined in the class If not explicitly initialized, then they'll be set to their defaults, so if schemaExists is a boolean (primitive) then false.
I'd suggest that what you want to do if you want to setup something for all tests to share is create a #BeforeClass static method to initialize a static property.
This will ensure it's run only once for the given test class, before any test methods are run
It's very clear to others reading your code what the intention was for the method
Here's an example with the DB schema initialization code in your OP:
#BeforeClass
public static void setupDBOnce() {
Connection connection = dataSource.getConnection();
Statement statement = connection.createStatement();
statement.execute(getSQLByFileName(GOLF_COURSE_TABLE_CREATION_SCRIPT));
statement.execute(getSQLByFileName(GOLF_COURSE_HOLE_TABLE_CREATION_SCRIPT));
connection.commit();
}
If for some reason you don't want this behavior (one instance per test method run) you can do any of these:
Annotate your class with #TestInstance(Lifecycle.PER_CLASS)
Pass the following VM arg: -Djunit.jupiter.testinstance.lifecycle.default=per_class
Create or add to an existing property file named junit-platform.properties found in the source root of the class path the entry: junit.jupiter.testinstance.lifecycle.default = per_class
If you do override the default, one note worth remembering from the docs:
When using this mode, a new test instance will be created once per test class. Thus, if your test methods rely on state stored in instance variables, you may need to reset that state in #BeforeEach or #AfterEach methods.
I know Java loads Classes in first Access (creating new Instance, calling static method or static field), but in this simple example I try to execute a jar file that uses some classes which there aren't in my ClassPath at run time. I expect (because of loading classes in first access) print my messages in static block and main method before an exception occurred. but I got "Exception in thread "main" java.lang.NoClassDefFoundError: com/example/DateAbstract" and nothing printed.
This occurred when I used an abstract class or interface in main class which that classes or interfaces are in another jar file.
public class Driver {
static { System.out.println("I am first.[static block]"); }
public static void main(String[] args) {
System.out.println("I am first.[ main method]");
DateAbstract date = new CustomDate();
System.out.println(date.sayDate());
}
in my another jar :
public class CustomDate extends DateAbstract {
#Override
public String sayDate() {
return new Date().toString();
}
public abstract class DateAbstract {
public abstract String sayDate();
}
when I use this code for add my classes to classpath at runtime. nothing changed. I got execption before execute static block.
public class Driver {
static {
System.out.println("I am first.[static block]");
try {
URL url = new File("lib/DateApi.jar").toURI().toURL();
URLClassLoader urlClassLoader = (URLClassLoader) URLClassLoader.getSystemClassLoader();
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(urlClassLoader,url);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
System.out.println("I am first.[ main method]");
DateAbstract date = new CustomDate();
System.out.println(date.sayDate());
}
}
Questions :
why is this happening and how to solve it ?
It’s not correct to say that in Java classes are loaded on their first access. You are confusing this with the initialization of a class, which implies executing the Java code of static initializer blocks and field initializers. The loading and verification might happen at an earlier time; the specification provides some freedom to the JVMs in this regard.
The key point here is that your main method instantiates an object of type CustomDate, stores it into a variable of the compile-time type DateAbstract and then tries to invoke sayDate() on that variable. This combination of instantiating CustomDate and invoking DateAbstract.sayDate() on it requires the verification of its correctness, i.e. whether CustomDate is a subtype DateAbstract. So the loading of these two classes will already happen at verification time.
You can easily check that this is the cause. If you change the type of the local variable date to CustomDate, the instantiated type and the receiver type of the method invocation are the same, so the correctness can be proven without loading the type, so it will be indeed deferred to the actual attempt to instantiate CustomDate, hence the messages will be printed.
Still, the loading time is an implementation-specific detail. A different JVM could load the referenced classes eagerly, even if they are not required for verification. The only safe way to ensure a deferred loading, is to use dynamic loading, e.g. Class.forName(String). Note that within the class detached this way, all types might be again referenced ordinarily. So if you do the dynamic loading once after the class path has been adjusted, there is not much impact on how you have to write the code nor its performance. Of course, having the code adjusting the class path and the code depending on it within the same class won’t work reliably.
I have a class, which has an Initialize method, which creates a bunch of tables in a database. This class looks like this:
public class MyClass
{
private bool initialized = false;
public void Initialize()
{
if(!initialized)
{
//Install Database tables
initialized = true;
}
}
public void DoSomething()
{
//Some code which depends on the database tables being created
}
public void DoSomethingElse()
{
//Some other code which depends on the database tables being created
}
}
The two methods DoSomething and DoSomethingElse need to make sure that the Initialize method has been called before proceeding because they depend on having the tables in the database. I have two choices:
Call the Initialize method in the constructor of the class - this does not seem like a good idea because constructors should now call methods, which are non-trivial and could cause an exception.
Call the Initialize method in each of the two methods - this does not seem like a great solution either especially if there are more than a handful of methods.
Is there a design pattern which could solve this in a more elegant way?
I would use a static factory method in which Initialize is invoked, and make the constructor private, to force use of the static factory method:
public class MyClass
{
private MyClass() { ... }
public static MyClass createInstance() {
MyClass instance = new MyClass();
instance.Initialize();
return instance;
}
}
Also, I would remove the initialized variable - in part because you don't need it any more - but also because it requires some means of guaranteeing visibility (e.g. synchronization, volatile or AtomicBoolean) for thread safety.
I think that Miško Hevery's blog post on (not) doing work in constructors is an interesting read.
I would separate the installation of the database from the definition of tasks that depends on it:
static factory could be used for the database installation as pointed out by #andy-turner
and the repository pattern to do work on the database
I suggest this solution because if i understand correctly, you are concerned about the high number of tasks that depends on the database.
Using the dependency injection pattern the repository can get a reference to the database, so in your bootstrapping code you can execute the database installation once and then inject the reference to the database in all the repositories that depends on it.
I would recommend using a collaborator that does the initialisation. That way MyClass can easily be tested by substituting a mock for the initialiser collaborator. For example:
public class MyClass {
public MyClass(MyClassInitialiser initialiser) {
initialiser.initialize();
}
public void DoSomething() {
//Some code which depends on the database tables being created
}
public void DoSomethingElse() {
//Some other code which depends on the database tables being created
}
}
Or an alternative solution, the idea here is that you're breaking the single responsibility principle in MyClass. There is non-trivial initialisation behaviour (installing database tables) and behaviour on those tables in the same class. So you should separate those responsibilities into two different classes and pass one in as a collaborator to the other.
public class MyClass {
DatabaseCollaborator collaborator;
public MyClass(DatabaseCollaborator collaborator) {
this.collaborator = collaborator;
}
public void DoSomething() {
//Some code which depends on the database tables being created
collaborator.someMethod();
}
public void DoSomethingElse() {
//Some other code which depends on the database tables being created
collaborator.anotherMethod();
}
}
public class DatabaseCollaborator {
DatabaseConfig config;
public DatabaseCollaborator(DatabaseConfig config) {
this.config = config;
}
public void someMethod() {
}
public void anotherMethod() {
}
}
public class DatabaseConfig {
public DatabaseConfig() {
// initialize
}
}
When I want a class whose instances must be initialized exactly once but I want to defer initialization until right before it's necessary (at which point the caller may fail to call an Initialize function, find it inconvenient to do so, or etc.), I do it similar to how you've started out with your code, but I make the initialization method private and name it something like "EnsureInitialized". It uses a flag to track and early exit if initialization has already been done, and all functions which depend on initialization already having happened just call that function as their first line (after argument-checking).
If I expect the caller to control when this instance's initialization is done, I make the method public, name it "Init", track whether it has been run with a flag, handle idempotence or max-run-once inside the Init method however is appropriate for that class, and all methods which depend on Init having already been run will call a different, private method named "AssertIsInitialized" which will throw an exception with text like "Must call init on {class name} instance before using this function".
My goal with these different patterns is to be unambiguous about each method's expectations and operation regarding initialization within the class instance lifecycle, and provide discoverability (of the design or code bugs using it) and automatic behavior (in the case of the self-initializing class in my first paragraph) wherever I think each is most appropriate to what the rest of the application is doing.
Context:
java.io.File class has a static inner class method as follows:
LazyInitialization.temporaryDirectory();
[EDITED to add some more code]
My code below eventually calls the above line of code. An exception is thrown from within the temporaryDirectory() method, which in my context is fine/expected.
try {
File tempFile = File.createTempFile("aaa", "aaa");
} catch (Exception e) {
// handle exception
}
Then, when I next invoke the same method (createTempFile) again, I get a "java.lang.NoClassDefFound error - Could not initialize class java.io.File$LazyInitialization"
Question:
I assumed that the inner class LazyInitialization should have been loaded by the class loader when its static method was invoked, even though the inner method threw an exception. Yet, why am I seeing the NoClassDefFound error when invoking the second time? Is the original assumption incorrect?
When a static initialization code throws a runtime exception, it is wrapped by ExceptionInInitializerError and thrown in the context of the code triggering the class loading (if its an Error exception, it is not wrapped). At this point, the class failed loading. Therefore, any attempt to use it later will cause a NoClassDefFoundError.
Perhaps this is what you experience.