Liferay 7.2 with JAX-RS/JAXB and JDK 11 Issue - jaxb

I have created a Liferay Blade "rest" module with the sample code that is provided with that template. I am trying to access the sample code's /greetings endpoint at: http://localhost:8080/o/greetings
The error I'm receiving appears to be common and well-documented because in Java 11, JAXB was completely removed from the JDK altogether:
JAXBException occurred : Implementation of JAXB-API has not been found on module path or classpath.. com.sun.xml.internal.bind.v2.ContextFactory cannot be found by org.apache.aries.jax.rs.whiteboard_1.0.4
The module builds and deploys into Liferay 7.2 with gradle, with no errors and the suggested solutions are not resolving the error (obviously).
Full disclosure, I am not a Java developer and therefore clearly lack a very basic understanding of Java, which could be contributing to the problem.
I have tried including the suggested dependencies to my gradle.build file:
compile('javax.xml.bind:jaxb-api:2.3.0')
compile('javax.activation:activation:1.1')
compile('org.glassfish.jaxb:jaxb-runtime:2.3.0')
I have also tried downloading and deploying the jar files for the above dependencies into Liferay 7.2. No luck.
My gradle.build file:
dependencies {
compileOnly group: "javax.ws.rs", name: "javax.ws.rs-api", version: "2.1"
compileOnly group: "org.osgi", name: "org.osgi.service.component.annotations", version: "1.3.0"
compileOnly group: "org.osgi", name: "org.osgi.service.jaxrs", version: "1.0.0"
compileOnly group: "com.liferay.portal", name: "com.liferay.portal.kernel", version: "4.4.0"
}
The sample class file:
package some.random.super.long.folder.path;
import java.util.Collections;
import java.util.Set;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.model.User;
import com.liferay.portal.kernel.service.UserLocalServiceUtil;
import com.liferay.portal.kernel.util.PropsUtil;
import javax.net.ssl.HttpsURLConnection;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Application;
import javax.ws.rs.ServerErrorException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.SecurityContext;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants;
/**
* #author andrew
*/
#Component(
property = {
JaxrsWhiteboardConstants.JAX_RS_APPLICATION_BASE + "=/greetings",
JaxrsWhiteboardConstants.JAX_RS_NAME + "=Greetings.Rest"
},
service = Application.class
)
public class DiningRestServiceApplication extends Application {
public Set<Object> getSingletons() {
return Collections.<Object>singleton(this);
}
#GET
#Produces("text/plain")
public String working() {
return "It works!";
}
#GET
#Path("/morning")
#Produces("text/plain")
public String hello() {
return "Good morning!";
}
#GET
#Path("/morning/{name}")
#Produces("text/plain")
public String morning(
#PathParam("name") String name,
#QueryParam("drink") String drink) {
String greeting = "Good Morning " + name;
if (drink != null) {
greeting += ". Would you like some " + drink + "?";
}
return greeting;
}
}
The expected result I am after is to receive the sample messages at the specified sample's endpoints.
Any help from this wonderful community would be greatly appreciated!
UPDATE
I switched to Java 9 JDK on my machine. I'm still experiencing the aforementioned error message.

Jorge Diaz of the Liferay community just responded in the Liferay forum stating that this looks like an existing bug that is currently being worked on.
https://issues.liferay.com/browse/LPS-92576
https://issues.liferay.com/browse/LPS-97968
Regardless, I confirmed that the combination of Liferay and Java 9 and 11 are not playing nicely with JAXB by downgrading to Java 8, which worked.

Liferay ships an implementation for JAXB in the product. We just need to configure the JVM to look for it instead of trying to look for the default old one.
Just setting the property javax.xml.bind.JAXBContextFactory=com.sun.xml.bind.v2.ContextFactory should do it. You should be able to set it on your environment or executable for the JVM that starts Liferay.
It should be set by default if later Liferay versions.

The solution provided by Carlos Sierra works. Add
-Djavax.xml.bind.JAXBContextFactory=com.sun.xml.bind.v2.ContextFactory
to the list of VM arguments to point to ContextFactory implementation provided by Liferay.
Environment: openjdk version "11.0.5" 2019-10-15 with Liferay DXP 7.2.10 GA1 SP 2 (dxp-2-7210)

Related

Objenesis dependency causes instantiation error

Just starting a new Gradle project.
This test passes:
def 'Launcher.main should call App.launch'(){
given:
GroovyMock(Application, global: true)
when:
Launcher.main()
then:
1 * Application.launch( App, null ) >> null
}
... until, to get another test using a (Java) Mock to work, I have to add these dependencies:
testImplementation 'net.bytebuddy:byte-buddy:1.10.8'
testImplementation 'org.objenesis:objenesis:3.1'
(NB I assume these versions are OK for Groovy 3.+, which I'm now using ... both are the most up-to-date available at Maven Repo).
With these dependencies the above test fails:
java.lang.InstantiationError: javafx.application.Application
at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:48)
at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73)
at org.objenesis.ObjenesisHelper.newInstance(ObjenesisHelper.java:44)
at org.spockframework.mock.runtime.MockInstantiator$ObjenesisInstantiator.instantiate(MockInstantiator.java:45)
at org.spockframework.mock.runtime.MockInstantiator.instantiate(MockInstantiator.java:31)
at org.spockframework.mock.runtime.GroovyMockFactory.create(GroovyMockFactory.java:57)
at org.spockframework.mock.runtime.CompositeMockFactory.create(CompositeMockFactory.java:42)
at org.spockframework.lang.SpecInternals.createMock(SpecInternals.java:47)
at org.spockframework.lang.SpecInternals.createMockImpl(SpecInternals.java:298)
at org.spockframework.lang.SpecInternals.createMockImpl(SpecInternals.java:288)
at org.spockframework.lang.SpecInternals.GroovyMockImpl(SpecInternals.java:215)
at core.AppSpec.Launcher.main should call App.launch(first_tests.groovy:30)
I confess that I have only the sketchiest notion of what "bytebuddy" and "objenesis" actually do, although I assume it is fiendishly clever. Edit: having just visited their respective home pages my notion is now slightly less sketchy, and yes, it is fiendishly clever.
If an orthodox solution to this is not available, is it by any chance possible to turn off the use of these dependencies for an individual feature (i.e. test)? Possibly using some annotation maybe?
Edit
This is an MCVE:
Specs: Java 11.0.5, OS Linux Mint 18.3.
build.gradle:
plugins {
id 'groovy'
id 'java'
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.8'
}
repositories { mavenCentral() }
javafx {
version = "11.0.2"
modules = [ 'javafx.controls', 'javafx.fxml' ]
}
dependencies {
implementation 'org.codehaus.groovy:groovy:3.+'
testImplementation 'junit:junit:4.12'
testImplementation 'org.spockframework:spock-core:2.0-M2-groovy-3.0'
testImplementation 'net.bytebuddy:byte-buddy:1.10.8'
testImplementation 'org.objenesis:objenesis:3.1'
// in light of kriegaex's comments:
implementation group: 'cglib', name: 'cglib', version: '3.3.0'
}
test { useJUnitPlatform() }
application {
mainClassName = 'core.Launcher'
}
installDist{}
main.groovy:
class Launcher {
static void main(String[] args) {
Application.launch(App, null )
}
}
class App extends Application {
void start(Stage primaryStage) {
}
}
first_tests.groovy:
class AppSpec extends Specification {
def 'Launcher.main should call App.launch'(){
given:
GroovyMock(Application, global: true)
when:
Launcher.main()
then:
1 * Application.launch( App, null ) >> null
}
}
The reason why this project needs something to call the Application subclass is explained here: it's so that it is possible to do an installDist which bundles in JavaFX.
Don't we have to use a global GroovyMock?
If you want to check the interaction, yes. But actually you are testing the JavaFX launcher rather than your application. So I doubt that there is any benefit. I would focus on testing the App class instead. Also imagine for a moment that you would write the classes with main methods in Java instead of Groovy. Groovy mocks would not work when called from Java code, especially not global ones. Then you would end up testing via Powermockito from Spock, which would also work but still you would test the JavaFX launcher rather than your application.
Also isn't it slightly extreme to say any use of Groovy mocks is wrong?
I did not say that. I said: "probably something is wrong with your application design". The reason I said that is because the use of Groovy mocks and things like mocking static methods are test code smells. You can check the smell and then decide it is okay, which IMO in most cases it is not. Besides, instead of application design the problem can also be in the test itself, which in this case I would say it is. But that is arguable, so I am going to present a solution to you further below.
In this case technically the global Application mock is your only way if you do insist to test the JavaFX launcher because even a global mock on App would not work as the launcher uses reflection in order to call the App constructor and that is not intercepted by the mock framework.
you say that Spock spock-core:2.0-M2-groovy-3.0 is a "pre-release". I can't see anything on this page (...) which says that. How do you know?
You found out already by checking out the GitHub repository, but I was just seeing it in the unusual version number containing "M2" like "milestone 2" which is similar to "RC" (or "CR") for release candidates (or candidate releases).
As for the technical problem, you can either not declare Objenesis in your Gradle script because it is an optional dependency, then the test compiles and runs fine, as you already noticed yourself. But assuming you need optional dependencies like Objenesis, CGLIB (actually cglib-nodep), Bytebuddy and ASM for other tests in your suite, you can just tell Spock not to use Objenesis in this case. So assuming you have a Gradle build file like this:
plugins {
id 'groovy'
id 'java'
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.8'
}
repositories { mavenCentral() }
javafx {
version = "11.0.2"
modules = ['javafx.controls', 'javafx.fxml']
}
dependencies {
implementation 'org.codehaus.groovy:groovy:3.+'
testImplementation 'org.spockframework:spock-core:2.0-M2-groovy-3.0'
// Optional Spock dependencies, versions matching the ones listed at
// https://mvnrepository.com/artifact/org.spockframework/spock-core/2.0-M2-groovy-3.0
testImplementation 'net.bytebuddy:byte-buddy:1.9.11'
testImplementation 'org.objenesis:objenesis:3.0.1'
testImplementation 'cglib:cglib-nodep:3.2.10'
testImplementation 'org.ow2.asm:asm:7.1'
}
test { useJUnitPlatform() }
application {
mainClassName = 'de.scrum_master.app.Launcher'
}
installDist {}
My version of your MCVE would looks like this (sorry, I added my own package names and also imports because otherwise it is not really an MCVE):
package de.scrum_master.app
import javafx.application.Application
import javafx.scene.Scene
import javafx.scene.control.Label
import javafx.scene.layout.StackPane
import javafx.stage.Stage
class App extends Application {
#Override
void start(Stage stage) {
def javaVersion = System.getProperty("java.version")
def javafxVersion = System.getProperty("javafx.version")
Label l = new Label("Hello, JavaFX $javafxVersion, running on Java $javaVersion.")
Scene scene = new Scene(new StackPane(l), 640, 480)
stage.setScene(scene)
stage.show()
}
}
package de.scrum_master.app
import javafx.application.Application
class Launcher {
static void main(String[] args) {
Application.launch(App, null)
}
}
package de.scrum_master.app
import javafx.application.Application
import spock.lang.Specification
class AppSpec extends Specification {
def 'Launcher.main should call App.launch'() {
given:
GroovyMock(Application, global: true, useObjenesis: false)
when:
Launcher.main()
then:
1 * Application.launch(App, null)
}
}
The decisive detail here is the useObjenesis: false parameter.
Update: Just for reference, this is how you would do it with a launcher class implemented in Java using PowerMockito.
Attention, this solution needs the Sputnik runner from Spock 1.x which was removed in 2.x. So in Spock 2 this currently does not work because it is based on JUnit 5 and can no longer use #RunWith(PowerMockRunner) and #PowerMockRunnerDelegate(Sputnik) because PowerMock currently does not support JUnit 5. But I tested it with Spock 1.3-groovy-2.5 and Groovy 2.5.8.
package de.scrum_master.app
import javafx.application.Application
import org.junit.runner.RunWith
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner
import org.powermock.modules.junit4.PowerMockRunnerDelegate
import org.spockframework.runtime.Sputnik
import spock.lang.Specification
import static org.mockito.Mockito.*
import static org.powermock.api.mockito.PowerMockito.*
#RunWith(PowerMockRunner)
#PowerMockRunnerDelegate(Sputnik)
#PrepareForTest(Application)
class JavaAppSpec extends Specification {
def 'JavaLauncher.main should launch JavaApp'() {
given:
mockStatic(Application)
when:
JavaLauncher.main()
then:
verifyStatic(Application, times(1))
Application.launch(JavaApp)
}
}

GORM setup using Gradle and Groovy

Can anyone please share the steps to setup GORM using gradle and use the same in groovy ?
GORM for Hibernate has excellent documentation
Particularly the section of Using GORM For Hibernate Outside Grails
At minimum you need:
compile "org.grails:grails-datastore-gorm-hibernate5:6.1.10.RELEASE"
runtime "com.h2database:h2:1.4.192"
runtime "org.apache.tomcat:tomcat-jdbc:8.5.0"
runtime "org.apache.tomcat.embed:tomcat-embed-logging-log4j:8.5.0"
runtime "org.slf4j:slf4j-api:1.7.10"
Entities should go under src/main/groovy
#Entity
class Person implements GormEntity<Person> {
String firstName
String lastName
static constraints = {
firstName blank:false
lastName blank:false
}
}
and then finally bootstrap the data store somewhere:
import org.grails.orm.hibernate.HibernateDatastore
Map configuration = [
'hibernate.hbm2ddl.auto':'create-drop',
'dataSource.url':'jdbc:h2:mem:myDB'
]
HibernateDatastore datastore = new HibernateDatastore( configuration, Person)

Cassandra 3.10 Create Trigger, class doesn't exist

I have DSE 5.1 with Cassandra 3.10 and cql 5.0.1 installed on CentOS 7.3.1611 (Core).
I'm following the tutorial from DSE Triggers:
http://docs.datastax.com/en/dse/5.1/cql/cql/cql_reference/cql_commands/cqlCreateTrigger.html?hl=trigger
Which send me to github:
https://github.com/apache/cassandra/tree/trunk/examples/triggers
According to the tutorial, I am compiling the jar with ANT 1.10.1. The compiled jar contain the code:
package org.apache.cassandra.triggers;
import java.io.InputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.Properties;
import org.apache.cassandra.schema.TableMetadata;
import org.apache.cassandra.schema.Schema;
import org.apache.cassandra.db.Mutation;
import org.apache.cassandra.db.partitions.Partition;
import org.apache.cassandra.db.partitions.PartitionUpdate;
import org.apache.cassandra.io.util.FileUtils;
import org.apache.cassandra.utils.FBUtilities;
import org.apache.cassandra.utils.UUIDGen;
public class AuditTrigger implements ITrigger
{
private Properties properties = loadProperties();
public Collection<Mutation> augment(Partition update)
{
String auditKeyspace = properties.getProperty("keyspace");
String auditTable = properties.getProperty("table");
TableMetadata metadata = Schema.instance.getTableMetadata(auditKeyspace, auditTable);
PartitionUpdate.SimpleBuilder audit = PartitionUpdate.simpleBuilder(metadata, UUIDGen.getTimeUUID());
audit.row()
.add("keyspace_name", update.metadata().keyspace)
.add("table_name", update.metadata().table)
.add("primary_key", update.metadata().partitionKeyType.getString(update.partitionKey().getKey()));
return Collections.singletonList(audit.buildAsMutation());
}
private static Properties loadProperties()
{
Properties properties = new Properties();
InputStream stream = AuditTrigger.class.getClassLoader().getResourceAsStream("AuditTrigger.properties");
try
{
properties.load(stream);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
finally
{
FileUtils.closeQuietly(stream);
}
return properties;
}
}
The compiled jar, I am copying to the cassandra triggers location (/etc/cassandra/triggers). Then I run from cql the command:
CREATE TRIGGER test1 ON test.test USING 'org.apache.cassandra.triggers.AuditTrigger';
And send me the error:
ConfigurationException: Trigger class 'org.apache.cassandra.triggers.AuditTrigger' doesn't exist
I copied the jar in all the nodes of my cluster, restarted the cluster and ran the command:
nodetool reloadtriggers
With no success, I also put in the jvm.options the command:
-Dcassandra.triggers_dir=/etc/dse/cassandra/triggers
And in the cassandra-env.sh, I added the command:
JVM_OPTS="$JVM_OPTS -Dcassandra.triggers_dir=/etc/dse/cassandra/triggers"
And I am getting the same error. I tryied adding the jar in the cassandra lib folder (/usr/share/dse/cassandra/lib/) and it seems to not been loading the compiled jar.
When I run the command in cql:
CREATE TRIGGER test1 ON test.test USING 'org.apache.cassandra.triggers.AuditTrigger';
I am still getting the same error
ConfigurationException: Trigger class 'org.apache.cassandra.triggers.AuditTrigger' doesn't exist
So, my question is, How can I make cassandra load my jar correctly and use it to create a trigger in cql?

Neo4j Spatial: can't run spatial

I have been trying to work with Neo4j Spatial for my project, but I can't make it work.
With limited documentation and examples I figured out how to load OSM map to the database. But to check if it is loaded, I am trying to execute a spatial query.
While trying to run my code I get this error:
import.java:69: error: cannot access GremlinGroovyPipeline
.startIntersectSearch(layer, bbox)
^
class file for com.tinkerpop.gremlin.groovy.GremlinGroovyPipeline not found
I understand what's wrong (it can't find the required library), but I don't know how to fix it. The reason is when I run Neo4j Spatial tests, LayerTest.java and TestSpatial.java do include GeoPipeline library and it works perfectly fine. However, when I created my simple java file to test Neo4j, and trying to execute commands that depend GeoPipeline library I get the error above.
I read the instructions on github for Neo4j and saw this note:
Note: neo4j-spatial has a mandatory dependency on
GremlinGroovyPipeline from the com.tinkerpop.gremlin.groovy package.
The dependency in neo4j is type 'provided', so when using
neo4j-spatial in your own Java project, make sure to add the following
dependency to your pom.xml, too.
However, I am not using Maven to build my app. It is a simple java file, that I want to run to test if I get how everything works.
here is the code from my java file:
package org.neo4j.gis.spatial;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.geotools.data.DataStore;
import org.geotools.data.neo4j.Neo4jSpatialDataStore;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.neo4j.gis.spatial.osm.OSMDataset;
import org.neo4j.gis.spatial.osm.OSMDataset.Way;
import org.neo4j.gis.spatial.osm.OSMGeometryEncoder;
import org.neo4j.gis.spatial.osm.OSMImporter;
import org.neo4j.gis.spatial.osm.OSMLayer;
import org.neo4j.gis.spatial.osm.OSMRelation;
import org.neo4j.gis.spatial.pipes.osm.OSMGeoPipeline;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import org.neo4j.kernel.impl.batchinsert.BatchInserter;
import org.neo4j.kernel.impl.batchinsert.BatchInserterImpl;
import org.neo4j.kernel.EmbeddedGraphDatabase;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.gis.spatial.pipes.GeoPipeline;
class SpatialOsmImport {
public static void main(String[] args)
{
OSMImporter importer = new OSMImporter("ott.osm");
Map<String, String> config = new HashMap<String, String>();
config.put("neostore.nodestore.db.mapped_memory", "90M" );
config.put("dump_configuration", "true");
config.put("use_memory_mapped_buffers", "true");
BatchInserter batchInserter = new BatchInserterImpl("target/dependency", config);
importer.setCharset(Charset.forName("UTF-8"));
try{
importer.importFile(batchInserter, "ott.osm", false);
batchInserter.shutdown();
GraphDatabaseService db = new EmbeddedGraphDatabase("target/dependency");
importer.reIndex(db, 10000);
db.shutdown();
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
GraphDatabaseService database = new EmbeddedGraphDatabase("target/dependency");
try{
SpatialDatabaseService spatialService = new SpatialDatabaseService(database);
Layer layer = spatialService.getLayer("layer_roads");
LayerIndexReader spatialIndex = layer.getIndex();
System.out.println("Have " + spatialIndex.count() + " geometries in " + spatialIndex.getBoundingBox());
Envelope bbox = new Envelope(-75.80, 45.19, -75.7, 45.23);
// Search searchQuery = new SearchIntersectWindow(bbox);
// spatialIndex.executeSearch(searchQuery);
// List<SpatialDatabaseRecord> results = searchQuery.getResults();
List<SpatialDatabaseRecord> results = GeoPipeline
.startIntersectSearch(layer, bbox)
.toSpatialDatabaseRecordList();
doGeometryTestsOnResults(bbox, results);
} finally {
database.shutdown();
}
}
private static void doGeometryTestsOnResults(Envelope bbox, List<SpatialDatabaseRecord> results) {
System.out.println("Found " + results.size() + " geometries in " + bbox);
Geometry geometry = results.get(0).getGeometry();
System.out.println("First geometry is " + geometry);
geometry.buffer(2);
}
}
It is very simple right now, but I can't make it work. How do I include com.tinkerpop.gremlin.groovy.GremlinGroovyPipeline in my app, so it works?
I run everything on Ubuntu 12.04 and java version "1.7.0_25", Java(TM) SE Runtime Environment (build 1.7.0_25-b15).
Any help is greatly appreciated.
the best way to get all the required dependencies in a place where you can include them in your classpath is to run
mvn dependency:copy-dependencies
in neo4j-spatial, and find the libs to include in target/deps, see http://maven.apache.org/plugins/maven-dependency-plugin/usage.html

Magento multiversion module Error class Mage_Catalog_Model_Resource_Product_Option not found

I'm trying to create module for magento. It use my own class
class Myfirm_Extname_Model_Mysql4_Product_Option extends Mage_Catalog_Model_Resource_Product_Option
In magento 1.7 all works fine, in 1.5 - error: Error class Mage_Catalog_Model_Resource_Product_Option not found.
How can I make class that will be inherited from Mage_Catalog_Model_Resource_Product_Option or Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Option depending on the version of magento?
I solved this prodblem.
protected function _getResource() {
if (version_compare(Mage::getVersion(), '1.6.0', '<')) {
$this->_resourceName = $this->_resourceName.'_oldversion';
}
if (empty($this->_resourceName)) {
Mage::throwException(Mage::helper('core')->__('Resource is not set.'));
}
return Mage::getResourceSingleton($this->_resourceName);
}
And then create 2 resource model class for old version of magento and new

Resources