Java 8 lambda myMap.stream (). count ()! = myMap.size () after merging myMap

EDIT: I found this to be an eclipse link bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=433075

ORIGINAL QUESTION:

In a JUnit test, I encountered unexpected behavior. As you can see the last statement fails because the stream does not seem to contain data and the map is not empty ?! I found out that it has something to do with jpa / eclipselink.

public class MyTest {
    private EntityManager em;

    @Before
    public void setUp() throws IOException {
            String dbFileName = "testDb.db";
            Map<String, Object> properties = new HashMap<String, Object>();
            properties.put(PersistenceUnitProperties.JDBC_URL, "jdbc:sqlite:"
                    + dbFileName);
            EntityManagerFactory factory = Persistence.createEntityManagerFactory("pul", properties);
            this.em = factory.createEntityManager();
    }

    @Test
    public void testStrange() {
        LV lv = new LV();
        // em.persist(lv); // this would work
        // em.merge(lv); // this would work as well
        lv = em.merge(lv); // this leads to the assertionError
        lv.getAms().add(new AM());
        assertEquals(1, lv.getAms().size()); // ok
        assertEquals(1, lv.getAms().stream().count()); // java.lang.AssertionError: expected:<1> but was:<0>
    }
}

      

LV:

@Entity
public class LV {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long _id;

    @OneToMany(mappedBy = "lv", cascade = CascadeType.ALL)
    private Collection<AM> ams = new HashSet<AM>();

    public LV() {
    }

    public Collection<AM> getAms() {
        return ams;
    }

}

      

AM:

@Entity
public class AM {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long _id;

    @ManyToOne
    private LV lv;

    public AM() {
    }

}

      

persistence.xml

<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
    version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
    <persistence-unit name="pul" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
            <property name="javax.persistence.jdbc.driver" value="org.sqlite.JDBC" />
            <!-- url is set during runtime -->
            <!-- <property name="javax.persistence.jdbc.url" value="jdbc:sqlite:sample.db" 
                /> -->
            <property name="javax.persistence.jdbc.user" value="" />
            <property name="javax.persistence.jdbc.password" value="" />

            <!-- EclipseLink should create the database schema automatically -->
            <property name="eclipselink.ddl-generation" value="create-tables" />
            <property name="eclipselink.ddl-generation.output-mode"
                value="database" />
        </properties>
    </persistence-unit>
</persistence>

      

pom.xml dependencies

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
    </dependency>
    <dependency>
        <groupId>org.xerial</groupId>
        <artifactId>sqlite-jdbc</artifactId>
        <version>3.8.6</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.persistence</groupId>
        <artifactId>eclipselink</artifactId>
        <version>2.6.0-M3</version>
    </dependency>

      

+3


source to share


1 answer


As Boann did, I tried to run your code (filling in simple implementations for the classes for which you didn't show the code ( LV

, AbstractModule

) and initialization LV

) and I get the expected result:

2
before:short2
2
in map:short2, in map:short1
short2, short1
2

      

So my guess is that the problem is not in the code you showed here, but in the code for LV or AbstractModule, or perhaps you are not importing the classes that you think you are. Finally, can I assume that another thread is down, which might modify the collection ams

?

For comparison, this is my dummy implementation of your classes.

AbstractModule:

public class AbstractModule {

    String kurzbezeichnung;

    public AbstractModule(String desc) {
        this.kurzbezeichnung = desc;
    }

    public String getKurzbezeichnung() {
        return this.kurzbezeichnung;
    }

}

      

LV:

public class LV {
    HashSet<AbstractModule> ams;

    public LV(HashSet<AbstractModule> abstractModules) {
        this.ams = abstractModules;
    }

    public Collection<AbstractModule> getAbstractModules() {
        return ams;
    }
}

      



initialization:

HashSet<AbstractModule> initialAms = new HashSet<AbstractModule>();
AbstractModule short1 = new AbstractModule("short1");
AbstractModule short2 = new AbstractModule("short2");
initialAms.add(short2);
initialAms.add(short1);
LV lv = new LV(initialAms);

      

EDIT :

After looking at the updated question and realizing that all of these classes are actually persistent databases, I think the problem may be related to lazy loading. May I suggest that you changed your definition of ams to

@OneToMany(mappedBy = "lv", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Collection<AM> ams = new HashSet<AM>();

      

As you can see from the discussion below, it turns out that EclipseLink implements the ams collection as org.eclipse.persistence.indirection.IndirectSet

, which is a lazy loaded implementation. But this class does not implement the method stream()

.

As the OP pointed out, there is a bug report for EchipseLink: https://bugs.eclipse.org/bugs/show_bug.cgi?id=433075

+2


source







All Articles