Akka Actors fails, VerifyError: Inconsistent stack

2019-06-25 08:28发布

问题:

I have a Java application where I use Akka Typed Actors. The code has no errors in Eclipse, but when I start my application it crashes and prints this error:

Exception in thread "main" java.lang.VerifyError: Inconsistent stackmap frames at branch target 266 in method com.example.actors.DBActor.getItems(Lorg/joda/time/DateTime;Lorg/joda/time/DateTime;)I at offset 170
    at com.example.ui.Main$1.create(Main.java:31)
    at akka.actor.TypedActor$$anonfun$newInstance$3.apply(TypedActor.scala:677)
    at akka.actor.TypedActor$$anonfun$newInstance$3.apply(TypedActor.scala:677)
    at akka.actor.TypedActor$.newTypedActor(TypedActor.scala:847)
    at akka.actor.TypedActor$$anonfun$newInstance$1.apply(TypedActor.scala:601)
    at akka.actor.TypedActor$$anonfun$newInstance$1.apply(TypedActor.scala:601)
    at akka.actor.LocalActorRef.akka$actor$LocalActorRef$$newActor(ActorRef.scala:1084)
    at akka.actor.LocalActorRef$$anonfun$2.apply(ActorRef.scala:628)
    at akka.actor.LocalActorRef$$anonfun$2.apply(ActorRef.scala:628)
    at akka.util.ReentrantGuard.withGuard(LockUtil.scala:20)
    at akka.actor.LocalActorRef.<init>(ActorRef.scala:628)
    at akka.actor.Actor$.actorOf(Actor.scala:249)
    at akka.actor.TypedActor$.newInstance(TypedActor.scala:677)
    at akka.actor.TypedActor.newInstance(TypedActor.scala)
    at com.example.ui.Main.main(Main.java:29)

I don't understand what can be wrong. I have check my com.example.actors.DBActor.getItems() but there is no error in it. What could be wrong?


UPDATE

Below is example on code where I get this error. I have these jar-files on the "Build path" in Eclipse:

  • derby.jar (from JDK7) (only an in-memory database is used in this example)
  • akka-actor-1.2.jar
  • akka-typed-actor-1.2.jar
  • aspectwerkz-2.2.3.jar
  • scala-library.jar

Here is the code:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import akka.actor.TypedActor;
import akka.actor.TypedActorFactory;


public class App {

    public App() {
        TypedActor.newInstance(Backend.class, new TypedActorFactory() {
            public TypedActor create() {
                return new DataActor();
            }
        });
    }

    class DataActor extends TypedActor implements Backend {

        @Override
        public void insertData(String msg) {
            final String sqlSelect = "SELECT msg FROM SESSION.messages "+
                                     "WHERE to_user_id = ? AND from_user_id = ?";
            final String connectionURL = "jdbc:derby:memory:memdatabase;create=true";

            /* if this declaration is moved to where the string is used 
               in the conditional, the conditional can be used */
            String result;

            try(Connection conn = DriverManager.getConnection(connectionURL);) {

                try(PreparedStatement ps = conn.prepareStatement(sqlSelect);
                    ResultSet rs = new QueryHelper(ps)
                                    .integer(13).integer(26).executeQuery();) {

                    /* this doesn't work */

                    result = (rs.next()) ? rs.getString("text")
                                         : null;

                    /* but this work:

                     String result = (rs.next()) ? rs.getString("text")
                                                 : null;
                     */

                    /* this works fine 

                    while(rs.next()) {
                        result = rs.getString("msg");
                    }                                   */
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    class QueryHelper {
        private final PreparedStatement ps;
        private int index = 1;

        public QueryHelper(PreparedStatement ps) {
            this.ps = ps;
        }

        public QueryHelper integer(int param) throws SQLException {
            ps.setInt(index++, param);
            return this;
        }

        public ResultSet executeQuery() throws SQLException {
            return ps.executeQuery();
        }
    }

    public interface Backend {
        public void insertData(String text);
    }

    public static void main(String[] args) {
        new App();
    }
}

回答1:

I have found out that this bug is in places where I use multiple resources in a single Java 7 try-with-resources statement.

E.g. this code will have the bug:

try (Connection conn = DriverManager.getConnection(connURL);
     PreparedStatement ps = conn.prepareStatement(sql);) {

    // do something

} catch (SQLException e) {
    e.printStackTrace();
}

and a workaround would look like:

try (Connection conn = DriverManager.getConnection(connURL);) {
    try (PreparedStatement ps = conn.prepareStatement(sql);) {

        // do something

    }
} catch (SQLException e) {
    e.printStackTrace();
}


回答2:

run java with the option -XX:-UseSplitVerifier