1

I have set a lazy collection up, as the rest payload over Jersey is too much, and I don't actually need this particular collection populated all the time.

I set the collection to Lazy, expecting it to not be present in my rest response, but it is still being populated.

Is Jersey somehow triggering the population of the collection somehow?

@OneToMany(mappedBy="gpt", orphanRemoval = false, cascade = { javax.persistence.CascadeType.PERSIST, javax.persistence.CascadeType.MERGE }, fetch = FetchType.LAZY)
    @XmlElement     
    @XmlInverseReference(mappedBy = "gpt")
    protected List<PrOpalProject> projects;

I am using spring repositories, not sure that's relevant (?) and EclipseLink

EDIT:

My persistence.xml file is using static weaving and my pom.xml is as below:

persistence.xml

<properties>            
            <property name="eclipselink.target-database" value="Oracle"/>            
            <property name="eclipselink.ddl-generation" value="none"/>            
            <property name="eclipselink.weaving" value="static"/>     

        </properties>




<!-- This plugin ensures the EclipseLink static weaving -->
        <plugins>
            <plugin>
                <artifactId>eclipselink-staticweave-maven-plugin</artifactId>
                <groupId>au.com.alderaan</groupId>
                <version>1.0.4</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>weave</goal>
                        </goals>
                        <phase>process-classes</phase>
                        <configuration>
                            <logLevel>ALL</logLevel>
                        </configuration>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
                        <groupId>org.eclipse.persistence</groupId>
                        <artifactId>eclipselink</artifactId>
                        <version>${eclipselink.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>

        <!--This plugin's configuration is used to store Eclipse m2e settings only. 
            It has no influence on the Maven build itself. -->
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.eclipse.m2e</groupId>
                    <artifactId>lifecycle-mapping</artifactId>
                    <version>1.0.0</version>
                    <configuration>
                        <lifecycleMappingMetadata>
                            <pluginExecutions>
                                <pluginExecution>
                                    <pluginExecutionFilter>
                                        <groupId>au.com.alderaan</groupId>
                                        <artifactId>eclipselink-staticweave-maven-plugin</artifactId>
                                        <versionRange>[1.0.4,)</versionRange>
                                        <goals>
                                            <goal>weave</goal>
                                        </goals>
                                    </pluginExecutionFilter>
                                    <action>
                                        <execute>
                                            <runOnIncremental>true</runOnIncremental>
                                        </execute>
                                    </action>
                                </pluginExecution>
                            </pluginExecutions>
                        </lifecycleMappingMetadata>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>

UPDATE 2:

I have put some start up code in my app, and have enabled EclipseLink Logging at FINE level.

I have one lazy collection (projects) and one Eager collection (products)

public void init() {


          List<PrGPT> gpts = gptService.getAllGPTs();

          for (PrGPT prGPT : gpts) {
              System.out.println(prGPT.getProjects().size());
              System.out.println(prGPT.getProducts().size());
        }

In my console, only the call the getProjects.size() causes a SQL trigger...implying that with Jersey out of the equation, lazy loading is working. See console output below:

[EL Fine]: sql: 2014-10-13 16:48:16.896--ServerSession(2099597535)--Connection(347358184)--Thread(Thread[localhost-startStop-1,5,main])--SELECT ID, APPROVED_PRIORITY, DISEASE, DISEASE_AREA, DPOM_BPOM_PHASE, IMED, MOLECULE_OR_TYPE_OF_PRODUCT, PLANNING_STATUS, PROGRAM_CATEGORY_DESC, PROGRAM_TYPE_DESC, PROJECT_CODE, PROJECT_NM, STATE, PROJECT_TYPE, THERAPY_AREA, GPT FROM PR_OPAL_PROJECT WHERE (GPT = ?)
    bind => [17000]
0
0
[EL Fine]: sql: 2014-10-13 16:48:22.817--ServerSession(2099597535)--Connection(2007184558)--Thread(Thread[localhost-startStop-1,5,main])--SELECT ID, APPROVED_PRIORITY, DISEASE, DISEASE_AREA, DPOM_BPOM_PHASE, IMED, MOLECULE_OR_TYPE_OF_PRODUCT, PLANNING_STATUS, PROGRAM_CATEGORY_DESC, PROGRAM_TYPE_DESC, PROJECT_CODE, PROJECT_NM, STATE, PROJECT_TYPE, THERAPY_AREA, GPT FROM PR_OPAL_PROJECT WHERE (GPT = ?)
    bind => [17050]
0
0
[EL Fine]: sql: 2014-10-13 16:48:25.06--ServerSession(2099597535)--Connection(202457351)--Thread(Thread[localhost-startStop-1,5,main])--SELECT ID, APPROVED_PRIORITY, DISEASE, DISEASE_AREA, DPOM_BPOM_PHASE, IMED, MOLECULE_OR_TYPE_OF_PRODUCT, PLANNING_STATUS, PROGRAM_CATEGORY_DESC, PROGRAM_TYPE_DESC, PROJECT_CODE, PROJECT_NM, STATE, PROJECT_TYPE, THERAPY_AREA, GPT FROM PR_OPAL_PROJECT WHERE (GPT = ?)
    bind => [9500]
1
0

The call to "getProducts.size()" doesn't trigger SQL.

So I can only assume this is a Jersey "thing"...

Even though, reading around the internet, I have set my XMLAccessorType to be "@XmlAccessorType(XmlAccessType.FIELD)". This apparently should not cause the lazy loaded collection to be brought over.

Regards

i

smackenzie
  • 2,880
  • 7
  • 46
  • 99

3 Answers3

1

Indeed, this is most likely "the Jersey thing". The simplest way to prevent stuff like that is to create separate classes for DB entitites and Web Service's DTOs and map between them. If you don't want to write too much boilerplate code, use some mapper e.g Dozer.

This approach has other advantages. For instance you can generate DTO classes from XML Schema. But the most important thing is that it decouples your DB schema from your interface. This is definitely the preferred aproach for SOAP based Web Services(see the comments in Do Domain Classes usually get JPA or JAXB Annotations or both?). Since REST is by definition tied to underlaying resources it might be a different. However if your service is anything more than simple CRUD you should definitely consider refactoring, because this layered architecture gives you required flexibility.

Community
  • 1
  • 1
Tomasz W
  • 2,263
  • 1
  • 17
  • 22
  • Hi Blaise Doughan in that thread seems to advocate annotating via JPA and JAXB, both on the domain classes as I have done...and he co-developed EclipseLink Moxy...thanks for response, not used DTO's before will have to do some research. – smackenzie Oct 20 '14 at 20:11
0

Ensure that your Entities are being woven. Lazy loading does not work if you aren't using runtime/build time weaving.

Rick
  • 3,830
  • 1
  • 18
  • 16
  • Not an expert in this field, where should I be checking? Thanks by the way! – smackenzie Oct 10 '14 at 14:32
  • I have this set in my persistence.xml – smackenzie Oct 10 '14 at 14:45
  • Decompile your Entities to ensure that they have indeed been woven. – Rick Oct 12 '14 at 21:48
  • How do I know if they are being woven correctly? I certainly see that it appears to be inmplementing the PersistenceWeaved interface...but what am I looking for? Could this just be a Jax-rs thing? – smackenzie Oct 13 '14 at 15:12
  • Not famililar with decompiling code...but doing some testing, I have added UPDATE 2 to original question. With Jersey out of the equation doing some testing on app startup...lazy loading is working. But REST response over Jersey has full payload. – smackenzie Oct 13 '14 at 15:54
0

I guess Jersey triggers the load because of the @XMLElement annotation. Perhaps is your problem similar to this question.

Community
  • 1
  • 1
bdulac
  • 1,686
  • 17
  • 26
  • Not sure this is related. Apparently using XMLAccessorType to FIELD should not trigger eager loading of a null collection. I am not sure if it is my use of XMLInverseReference as part of Moxy is causing this. – smackenzie Oct 15 '14 at 10:54
  • I guess the PrOpalProjects of the list are instantiated with the default constructor. Can you try to set a breakpoint on the default constructor to check which component is responsible for loading the list content when executing in Jersey ? – bdulac Oct 16 '14 at 18:34
  • It must be that to traverse the object graph, Jersey polls the field, or checks the array size and thus triggers the load of the collection? If that's the case....lazy loading can't work. Not sure if it's Moxy related. Will take a look at the constructor when I am able to. Without Jersey...lazy loading works. – smackenzie Oct 16 '14 at 20:23