Reputation: 21
I have started learning Helidon MP for a while yet, in tutorials and almost every source code I read based on this micro-service framework, examples are written on H2 database. I couldn't find any example based on MongoDB up to now. I already know about the JPA platform that eclipselink has developed for MongoDB and tried the guides in the JPA/NoSQL Examples. Besides, I could actually run the tests successfully in a simple maven project and creating the EntityManager object using factory directly works fine. But putting it in a Helidon MP project and using CDI for EntityManager like the instructions causes exception when I access http://localhost:8080/person/sahand
with curl
command. Before I put the related codes, I just found out that when Helidon creates EntityManager for a NoSQL database access, it should use org.eclipse.persistence.eis.EISLogin
object while it's creating org.eclipse.persistence.sessions.DatabaseLogin
causing a ClassCastException at some point and so on.
This is the exception I get:
Caused by: Exception [EclipseLink-7108] (Eclipse Persistence Services - 2.7.7.v20200504-69f2c2b80d): org.eclipse.persistence.exceptions.ValidationException
Exception Description: This operation is not supported for non-relational platforms.
at org.eclipse.persistence.exceptions.ValidationException.notSupportedForDatasource(ValidationException.java:590)
at org.eclipse.persistence.internal.sessions.AbstractSession.getLogin(AbstractSession.java:2751)
at io.helidon.integrations.cdi.eclipselink.CDISEPlatform.initializeExternalTransactionController(CDISEPlatform.java:228)
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.preConnectDatasource(DatabaseSessionImpl.java:851)
at org.eclipse.persistence.internal.sessions.DatabaseSessionImpl.login(DatabaseSessionImpl.java:823)
at org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider.login(EntityManagerFactoryProvider.java:258)
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.deploy(EntityManagerSetupImpl.java:769)
This is the resource manager for database access:
@Path("/person")
@Dependent
public class PersonResourceManager {
@PersistenceContext
private EntityManager em;
@GET
@Path("/{name}")
@Produces("text/plain")
@Transactional
public String getResponse(@PathParam("name") String name) {
Query query = em.createQuery("Select p from PERSON p where p.name LIKE '" + name + "'");
Person person = (Person) query.getResultList().get(0);
return String.valueOf(person.getAge()) + "\n";
}
}
Here is the Entity I'm trying to read from a MongoDB collection which is already created:
@Entity(name = "PERSON")
@NoSql(dataFormat = DataFormatType.MAPPED)
public class Person implements Serializable {
@Id
@GeneratedValue
@Field(name = "_id")
private String id;
@Basic
private String name;
@Basic
private int age;
@Version
private long version;
@Deprecated
protected Person() {}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getId() {return id;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
}
These are the maven dependencies related to database resolved in the project:
<dependency>
<groupId>javax.transaction</groupId>
<artifactId>javax.transaction-api</artifactId>
<version>1.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.resource</groupId>
<artifactId>connector-api</artifactId>
<version>1.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.helidon.integrations.cdi</groupId>
<artifactId>helidon-integrations-cdi-eclipselink</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.helidon.integrations.cdi</groupId>
<artifactId>helidon-integrations-cdi-jpa</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.helidon.integrations.cdi</groupId>
<artifactId>helidon-integrations-cdi-jta-weld</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.helidon.integrations.cdi</groupId>
<artifactId>helidon-integrations-cdi-datasource-hikaricp</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.12.6</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>2.7.7</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.nosql</artifactId>
<version>2.7.7</version>
</dependency>
Unit definition in persistence.xml
file:
<persistence-unit name="mongodb" transaction-type="RESOURCE_LOCAL">
<class>sahand.example.helidon.Person</class>
<properties>
<property name="eclipselink.target-database" value="org.eclipse.persistence.nosql.adapters.mongo.MongoPlatform"/>
<property name="eclipselink.nosql.connection-spec" value="org.eclipse.persistence.nosql.adapters.mongo.MongoConnectionSpec"/>
<property name="eclipselink.nosql.property.mongo.port" value="27017"/>
<property name="eclipselink.nosql.property.mongo.host" value="localhost"/>
<property name="eclipselink.nosql.property.mongo.db" value="jpa-nosql-demo"/>
<property name="eclipselink.logging.level" value="FINEST"/>
</properties>
</persistence-unit>
And finally a part of application.yaml
that I guess is correct. However, I'm kind of sure that exception happens before even reading this configuration.
javax:
sql:
DataSource:
person:
dataSourceClassName: othatrg.eclipse.persistence.nosql.adapters.mongo.MongoPlatform
dataSource:
url: mongodb://localhost:27017
user: sample_user
password: "samplePass"
I would be really grateful if someone could help me with this. Although it's possible to create every EntityManager object by factory, I feel like this solution is messy. Either I'm using wrong dependency or something else I don't know about. This is also the instruction I followed for Helidon and JPA.
Upvotes: 0
Views: 299
Reputation: 16238
This was a bug in Helidon in the sense that the JPA subsystem in Helidon was calling the relational-database-specific method Session#getLogin()
instead of the more apparently general-purpose Session#getDatasourceLogin()
method.
The fix should be available in Helidon 2.0.2. While it is not guaranteed to fix this issue, it is the right thing for Helidon to do nonetheless.
Upvotes: 0