PDA

View Full Version : Unable to set Injected field in JPA entity


swiegersf
08-03-2010, 11:03 AM
I'm trying to build a special type of JPA entity that will get dependencies injected via an InjectionTarget. Here is my class:


@Entity
@Table(name = "SwiegersF.SimpleJpaBean")
public class SimpleJpaBean {

@Inject
@Transient
Logger logger;

@Id
String uuid;

public SimpleJpaBean() {
uuid = UUID.randomUUID().toString();
}

}



However, upon starting Resin 4.0.8, I get the following error on the command line:


[12:54:05.014] {resin-37} com.caucho.amber.AmberRuntimeException: 'wargames.SimpleJpaBean' with classloader EnvironmentClassLoader[web-app:http://default/alchemy-no-test-app-web,starting] is an illegal instance class. The class has not been enhanced as implementing interface com.caucho.amber.entity.Entity.
at com.caucho.amber.type.AbstractEnhancedType.getInst anceClass(AbstractEnhancedType.java:281)
at com.caucho.amber.type.EntityType.getInstanceClass( EntityType.java:200)
at com.caucho.amber.entity.AmberEntityHome.init(Amber EntityHome.java:177)
at com.caucho.amber.manager.AmberPersistenceUnit.init EntityHomes(AmberPersistenceUnit.java:1422)
at com.caucho.amber.manager.AmberContainer.startPersi stenceUnits(AmberContainer.java:948)
at com.caucho.amber.manager.AmberContainer.start ...


If I take the @Inject out, then it works.

My guess is that Resin recognizes the bean as a CDI managed bean, and the JPA implementation doesn't like that for some reason (probably because the class has been modified?). Surely there is no problem having the same bean being both a JPA managed bean and a CDI managed bean, especially if it is a pseudo-scoped bean? I certainly don't see either spec explicitly forbidding this situation. In DDD, it is common to inject dependencies into your domain entities.

emil
08-04-2010, 10:42 PM
Hi,

You probably shouldn't be using Amber. It's definitely not been updated to be CDI aware yet and we're shipping EclipseLink now. Resin 4.0 will automatically select EclipseLink unless you've overridden it in a persistence.xml.

Best,
Emil

swiegersf
08-05-2010, 07:41 AM
Thanks for the response, Emil. I have not specifically set anything to use Amber - here is my persistence.xml:


<persistence xmlns="http://java.sun.com/xml/ns/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">
<persistence-unit name="wargames">
<jta-data-source>java:app/jdbc/wargamesDataSource</jta-data-source>
<class>wargames.SimpleJpaBean</class>
<exclude-unlisted-classes></exclude-unlisted-classes>
</persistence-unit>
</persistence>


Using 4.0.9, the above does use the EclipseLink JPA provider. But now I have another problem - my transaction is not committing any changes to the database. Is there a property I must set to tell EclipseLink to use Resin's transaction context (similar to Hibernate's hibernate.transaction.manager_lookup_class)? I had a look at the examples in the distribution, but I find nothing of the sort.

emil
08-05-2010, 06:35 PM
Hi,

Do you have some sample code? Resin's JTA should be plugging into JPA automatically without configuration, so it could be a bug. I just hit an issue in 4.0.9 where we were not intercepting calls to polymorphic methods properly (i.e. if you had foo() and foo(int), only one of them was being intercepted for XA).

Also, if you could turn on "finer" logging for "com.caucho", that will show the transaction boundaries versus where your code is running. That would show if the transactions are committing early or rolling back or something else incorrect.

Thanks,
Emil

swiegersf
08-06-2010, 09:12 AM
Hi Emil

I have a simple app that uses Hessian remoting. Here is my entity:


@Entity
public class Board implements Serializable {

/**
* Create a new Board.
*
* @return
*/
static Board newInstance() {
Board board = new Board();
board.uuid = UUID.randomUUID().toString();
board.squares = new ArrayList<Square>();
return board;
}

private static final long serialVersionUID = 1L;

Board() {
}

@SuppressWarnings("unused")
@Id
private String uuid;

@SuppressWarnings("unused")
@Version
private Integer version;

/**
* The number of horizontal squares.
*/
private Integer horizontalCount;

/**
* The number of vertical squares.
*/
private Integer verticalCount;

@OneToMany(cascade = CascadeType.ALL)
private List<Square> squares;

/**
* Generate the squares for the board.
*
* @param x
* @param y
*/
public void generateSquares(Integer x, Integer y) {
this.horizontalCount = x;
this.verticalCount = y;
this.squares.clear();
int total = x * y;
for (int k = 0; k < total; k++) {
Square square = new Square(this);
this.squares.add(square);
}
}

@Override
public String toString() {
return "Board (" + this.horizontalCount + " X " + this.verticalCount
+ ")";
}

}


Here is the Hessian Servlet I use:


public class HessianRemoteBoardRepository extends HessianServlet implements
BoardRepository {

private static final long serialVersionUID = 1L;

@Inject
private BoardRepository boardRepository;

public Board newInstance() {
return boardRepository.newInstance();
}

public void persist(Board board) {
boardRepository.persist(board);
}

}


which delegates to a stateless EJB:


@Stateless
@TransactionAttribute(TransactionAttributeType.REQ UIRED)
public class JpaBoardRepository implements BoardRepository, Serializable {

private static final long serialVersionUID = 1L;

@Inject
@WarGamesData
private EntityManager entityManager;

@Override
public Board newInstance() {
return Board.newInstance();
}

@Override
public void persist(Board board) {
entityManager.persist(board);
}

@Override
public String toString() {
return "JPA Board Repository (entityManager=" + entityManager + ")";
}

}


My client code (invoked from a main method elsewhere):


public class Game implements Serializable {

private static final long serialVersionUID = 1L;

public void play() throws Exception {

// Create the board.
// Board board = boardRepository.newInstance();

CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(new CookiePolicy() {

@Override
public boolean shouldAccept(URI uri, HttpCookie cookie) {
return true;
}

});

CookieHandler.setDefault(cookieManager);

HessianProxyFactory factory = new HessianProxyFactory();
BoardRepository boardRepository = (BoardRepository) factory
.create(BoardRepository.class,
"http://localhost:8080/alchemy-no-test-app-web/boardRepository");

Board board = boardRepository.newInstance();
board.generateSquares(2, 3);
boardRepository.persist(board);

}

}


After the above (which seems to work,), the database tables are not changed in any way.

The above works with Hibernate. But that increases my WAR file by 5MB :(

Apologies for the verbosity and thanks!
Francois

swiegersf
08-06-2010, 09:15 AM
And here is the server output of the above with my log level set to finest (note the odd SocketException which is not reported on level Info):


[11:01:29.261] {http://*:8080-2} Http[2] POST /alchemy-no-test-app-web/boardRepository HTTP/1.1
[11:01:29.261] {http://*:8080-2} Http[2] Remote-IP: 127.0.0.1:2593
[11:01:29.261] {http://*:8080-2} Http[2] Content-Type: x-application/hessian
[11:01:29.261] {http://*:8080-2} Http[2] Cache-Control: no-cache
[11:01:29.261] {http://*:8080-2} Http[2] Pragma: no-cache
[11:01:29.261] {http://*:8080-2} Http[2] User-Agent: Java/1.6.0_21
[11:01:29.261] {http://*:8080-2} Http[2] Host: localhost:8080
[11:01:29.261] {http://*:8080-2} Http[2] Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
[11:01:29.261] {http://*:8080-2} Http[2] Connection: keep-alive
[11:01:29.261] {http://*:8080-2} Http[2] Content-Length: 505
[11:01:29.261] {http://*:8080-2} Dispatch '/boardRepository' to WebAppFilterChain[http://localhost:8080/alchemy-no-test-app-web, next=ServletFilterChain[boardRepository]]
[11:01:29.261] {http://*:8080-2} call 2.0

[11:01:29.277] {http://*:8080-2} method "persist"

[11:01:29.292] {http://*:8080-2} map wargames.board.Board (#0)

[11:01:29.292] {http://*:8080-2} "uuid" => "eb63dbc4-9494-435e-aa83-d5e07529338d"

[11:01:29.292] {http://*:8080-2} "version" => null

[11:01:29.292] {http://*:8080-2} "horizontalCount" => 2

[11:01:29.292] {http://*:8080-2} "verticalCount" => 3

[11:01:29.292] {http://*:8080-2} "squares" => list (#1)

[11:01:29.308] {http://*:8080-2} 0: x6c

[11:01:29.308] {http://*:8080-2} 1: x00

[11:01:29.308] {http://*:8080-2} 2: x00

[11:01:29.308] {http://*:8080-2} 3: x00

[11:01:29.308] {http://*:8080-2} 4: x06

[11:01:29.371] {http://*:8080-2} 5: map wargames.board.Square (#2)

[11:01:29.371] {http://*:8080-2} "uuid" => null

[11:01:29.371] {http://*:8080-2} "version" => null

[11:01:29.371] {http://*:8080-2} "board" => ref #0

[11:01:29.371] {http://*:8080-2} 6: map wargames.board.Square (#3)

[11:01:29.371] {http://*:8080-2} "uuid" => null

[11:01:29.371] {http://*:8080-2} "version" => null

[11:01:29.371] {http://*:8080-2} "board" => ref #0

[11:01:29.371] {http://*:8080-2} 7: map wargames.board.Square (#4)

[11:01:29.371] {http://*:8080-2} "uuid" => null

[11:01:29.371] {http://*:8080-2} "version" => null

[11:01:29.371] {http://*:8080-2} "board" => ref #0

[11:01:29.371] {http://*:8080-2} 8: map wargames.board.Square (#5)

[11:01:29.371] {http://*:8080-2} "uuid" => null

[11:01:29.371] {http://*:8080-2} "version" => null

[11:01:29.371] {http://*:8080-2} "board" => ref #0

[11:01:29.371] {http://*:8080-2} 9: map wargames.board.Square (#6)

[11:01:29.371] {http://*:8080-2} "uuid" => null

[11:01:29.371] {http://*:8080-2} "version" => null

[11:01:29.386] {http://*:8080-2} "board" => ref #0

[11:01:29.386] {http://*:8080-2} 10: map wargames.board.Square (#7)

[11:01:29.386] {http://*:8080-2} "uuid" => null

[11:01:29.386] {http://*:8080-2} "version" => null

[11:01:29.386] {http://*:8080-2} "board" => ref #0

[11:01:29.386] {http://*:8080-2} Transaction[01:46b16acf] begin
[EL Info]: 2010-08-06 11:01:29.464--ServerSession(6395644)--EclipseLink, version: Eclipse Persistence Services - 2.0.0.v20091127-r5931
[11:01:29.777] {http://*:8080-2} create: ManagedPoolItem[java:app/jdbc/wargamesDataSource,0,ManagedConnectionImpl](active:0, total:0)
[11:01:29.792] {http://*:8080-2} Transaction[01:46b16acf] start-XA ManagedPoolItem[java:app/jdbc/wargamesDataSource,0,ManagedConnectionImpl]
[11:01:29.792] {http://*:8080-2} begin-local-XA: Xid[01:46b16acf] com.caucho.sql.ManagedConnectionImpl$LocalTransact ionImpl@1dd8136
[11:01:29.792] {http://*:8080-2} allocate ManagedPoolItem[java:app/jdbc/wargamesDataSource,0,ManagedConnectionImpl]
[11:01:29.855] {http://*:8080-2} sharing xa-pool item: ManagedPoolItem[java:app/jdbc/wargamesDataSource,0,ManagedConnectionImpl]
[11:01:29.855] {http://*:8080-2} sharing xa-pool item: ManagedPoolItem[java:app/jdbc/wargamesDataSource,0,ManagedConnectionImpl]
[EL Info]: 2010-08-06 11:01:29.98--ServerSession(6395644)--jar:file:/C:/java/resin/resin-4.0.9/webapps/alchemy-no-test-app-web/WEB-INF/lib/alchemy-no-test-app.jar!/_wargames login successful
[11:01:30.089] {http://*:8080-2} Transaction[01:46b16acf] commit (active)
[11:01:30.089] {http://*:8080-2} commit-local: com.caucho.sql.ManagedConnectionImpl$LocalTransact ionImpl@1dd8136
[11:01:30.089] {http://*:8080-2} idle ManagedPoolItem[java:app/jdbc/wargamesDataSource,0,ManagedConnectionImpl]
[11:01:30.089] {http://*:8080-2} Hessian 2.0

[11:01:30.089] {http://*:8080-2} Reply

[11:01:30.089] {http://*:8080-2} Http[2] HTTP/1.1 200 OK
[11:01:30.089] {http://*:8080-2} Http[2] Content-Type: application/x-hessian; charset=windows-1252
[11:01:30.089] {http://*:8080-2} Http[2] Transfer-Encoding: chunked
[11:01:30.089] {http://*:8080-2} Http[2] write-set-offset(175)
[11:01:30.089] {http://*:8080-2} Http[2] write-next-buffer(5)
[11:01:30.089] {http://*:8080-2} Http[2] flush()
[11:01:30.089] {http://*:8080-2} null

[11:01:30.089] {http://*:8080-2} Http[2] write-chunk-tail(7)
[11:01:30.089] {http://*:8080-2} Http[2] finish/keepalive
[11:01:30.152] {http://*:8080-2} java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream. java:168)
at com.caucho.vfs.SocketStream.read(SocketStream.java :187)
at com.caucho.vfs.SocketStream.readTimeout(SocketStre am.java:239)
at com.caucho.vfs.ReadStream.fillWithTimeout(ReadStre am.java:1134)
at com.caucho.network.listen.SocketLinkListener.keepa liveThreadRead(SocketLinkListener.java:1341)
at com.caucho.network.listen.TcpSocketLink.processKee palive(TcpSocketLink.java:688)
at com.caucho.network.listen.TcpSocketLink.handleRequ estsImpl(TcpSocketLink.java:621)
at com.caucho.network.listen.TcpSocketLink.handleRequ ests(TcpSocketLink.java:576)
at com.caucho.network.listen.TcpSocketLink$AcceptTask .doTask(TcpSocketLink.java:1157)
at com.caucho.network.listen.TcpSocketLink$Connection ReadTask.runThread(TcpSocketLink.java:1092)
at com.caucho.network.listen.TcpSocketLink$AcceptTask .run(TcpSocketLink.java:1124)
at com.caucho.env.thread.ResinThread.runTasks(ResinTh read.java:169)
at com.caucho.env.thread.ResinThread.run(ResinThread. java:126)
[11:01:30.152] {http://*:8080-2} TcpSocketLink[id=2,] closing connection TcpSocketLink[id=http://*:8080-2,http://*:8080,CLOSED], total=3