NoClassDefFound React Native Library Install Android - java

I am trying to install https://github.com/theopolisme/react-native-stripe-terminal on a fresh react native init project. When I try to initialize the library I get the following runtime error.
Error: Exception in HostObject::get for prop 'RNStripeTerminal': java.lang.NoClassDefFoundError: com.reactnative_stripeterminal.Constants, js engine: hermes
From my research it seems that package is not install properly. But I've tried both Auto Linking and manual installation with the same error. It doesn't seem like this library is very well maintained, but it could also be user error. I'm using react 67.4 and Java 11 on a Macbook M1. Current manual installation below.
app/build.gradle
dependencies {
implementation project(':react-native-stripe-terminal')
MainApplication.java
package com.stripeterminaldemo;
import android.app.Application;
import android.content.Context;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.reactnative_stripeterminal.RNStripeTerminalPackage;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.config.ReactFeatureFlags;
import com.facebook.soloader.SoLoader;
import com.stripeterminaldemo.newarchitecture.MainApplicationReactNativeHost;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost =
new ReactNativeHost(this) {
#Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
#Override
protected List<ReactPackage> getPackages() {
#SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
packages.add(new RNStripeTerminalPackage());
return packages;
}
#Override
protected String getJSMainModuleName() {
return "index";
}
};
private final ReactNativeHost mNewArchitectureNativeHost =
new MainApplicationReactNativeHost(this);
#Override
public ReactNativeHost getReactNativeHost() {
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
return mNewArchitectureNativeHost;
} else {
return mReactNativeHost;
}
}
#Override
public void onCreate() {
super.onCreate();
// If you opted-in for the New Architecture, we enable the TurboModule system
ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
SoLoader.init(this, /* native exopackage */ false);
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
}
/**
* Loads Flipper in React Native templates. Call this in the onCreate method with something like
* initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
*
* #param context
* #param reactInstanceManager
*/
private static void initializeFlipper(
Context context, ReactInstanceManager reactInstanceManager) {
if (BuildConfig.DEBUG) {
try {
/*
We use reflection here to pick up the class that initializes Flipper,
since Flipper library is not available in release mode
*/
Class<?> aClass = Class.forName("com.stripeterminaldemo.ReactNativeFlipper");
aClass
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
.invoke(null, context, reactInstanceManager);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
settings.gradle
rootProject.name = 'StripeTerminalDemo'
include ':react-native-stripe-terminal'
project(':react-native-stripe-terminal').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-stripe-terminal/android')
apply from: file("../node_modules/#react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':app'
includeBuild('../node_modules/react-native-gradle-plugin')
if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") {
include(":ReactAndroid")
project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid')
}

Related

Unable to integrate java code to my react native project - error: incompatible types: ReactApplicationContext cannot be converted to Activity

I am trying to bridge java code with my react native project.
My flow is this - when the user clicks on my pay button in react native, it routes to a page (which is a payment gateway) written in java and then when the user is done with the payment process it routes back to the initial page in react native.
I am getting the error below:
HelloWorldModule.java:56: error: incompatible types: ReactApplicationContext cannot be converted
to Activity
new RavePayManager((Activity)reactContext).setAmount(Double.parseDouble(String.valueOf(amount)))
Please see below my code:
//React native code to connect to java
// We are importing the native Java module here
import {NativeModules} from 'react-native';
var HelloWorld = NativeModules.HelloWorld;
// type Props = {};
export default class App extends Component {
// async function to call the Java native method
async sayHiFromJava() {
HelloWorld.sayHi( (err) => {console.log(err)}, (msg) => {console.log(msg)} );
}
render() {
return (
<View style={styles.container}>
<TouchableOpacity onPress={ this.sayHiFromJava }>
<Text>Invoke native Java code</Text>
</TouchableOpacity>
</View>
);
}
}
// MainApplication.java
package com.packagename;
import android.app.Application;
import android.content.Context;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.RNFetchBlob.RNFetchBlobPackage;
import com.reactnativecommunity.geolocation.GeolocationPackage;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.soloader.SoLoader;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import com.facebook.react.bridge.Callback;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost =
new ReactNativeHost(this) {
#Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
#Override
protected List<ReactPackage> getPackages() {
#SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
packages.add(new HelloWorldPackage(MainApplication.this)); ---- // added payment gateway
return packages;
}
#Override
protected String getJSMainModuleName() {
return "index";
}
};
#Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
#Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
initializeFlipper(this); // Remove this line if you don't want Flipper enabled
}
/**
* Loads Flipper in React Native templates.
*
* #param context
*/
private static void initializeFlipper(Context context) {
if (BuildConfig.DEBUG) {
try {
/*
We use reflection here to pick up the class that initializes Flipper,
since Flipper library is not available in release mode
*/
Class<?> aClass = Class.forName("com.facebook.flipper.ReactNativeFlipper");
aClass.getMethod("initializeFlipper", Context.class).invoke(null, context);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}
// HelloWorldModule.java - payment gateway code
package com.packagename;
import com.facebook.react.bridge.ReactApplicationContext;
import android.content.Context;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.uimanager.IllegalViewOperationException;
import com.flutterwave.raveandroid.RaveConstants;
import com.flutterwave.raveandroid.RavePayActivity;
import com.flutterwave.raveandroid.RavePayManager;
import android.app.Activity;
public class HelloWorldModule extends ReactContextBaseJavaModule {
Context context;
ReactApplicationContext reactContext;
public HelloWorldModule(ReactApplicationContext reactContext,Context context) {
super(reactContext); //required by React Native
this.reactContext= reactContext;
this.context= context;
}
#Override
//getName is required to define the name of the module represented in JavaScript
public String getName() {
return "HelloWorld";
}
#ReactMethod
public void sayHi(Callback errorCallback, Callback successCallback) {
// try {
// System.out.println("Greetings from Java");
// successCallback.invoke("Callback : Greetings from Java");
// } catch (IllegalViewOperationException e) {
// errorCallback.invoke(e.getMessage());
// }
try{
int amount = 100;//call.argument("amount");
String narration = "Payment for soup";//call.argument("nara");
String countryCode = "NG"; //call.argument("countryCode");
String currency = "NGN"; //call.argument("currency");
String amountText = "100";//call.argument("amountText");
String email = "haha#gmail.com";//call.argument("email");
String name = "King John";//call.argument("name");
String paymentId = "a98sjkhdjdu";//call.argument("paymentId");
String key ="*********-***********-X";
String secret = "*********-*********-X";
new RavePayManager((Activity)reactContext).setAmount(Double.parseDouble(String.valueOf(amount)))
.setCountry(countryCode)
.setCurrency(currency)
.setEmail(email)
.setfName(name)
.setlName("")
.setNarration(narration)
.setPublicKey(key)
.setTxRef(paymentId)
.acceptMpesaPayments(false)
.acceptAccountPayments(true)
.acceptCardPayments(true)
.acceptGHMobileMoneyPayments(false)
.onStagingEnv(false)
.initialize();
} catch (IllegalViewOperationException e) {
errorCallback.invoke(e.getMessage());
}
}
}
// HelloWorldPackage.java
package com.packagename;
import com.facebook.react.ReactPackage;
import android.content.Context;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import com.visioncapitaleye.HelloWorldModule;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class HelloWorldPackage implements ReactPackage {
Context context;
HelloWorldPackage(Context context) {
this.context = context;
}
#Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
#Override
public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
//this is where you register the module
modules.add(new HelloWorldModule(reactContext,context)); // added HelloWorldModule
return modules;
}
}
I am new to java and cant seem to figure out what I am doing wrong.
Please assist.
I had a similar issue while trying to integrate a sdk into an existing react-native project. Try the following to see if it works for you. Instead of casting reactContext into Activity, just get the current activity and use that.
final Activity activity = getCurrentActivity();

How to start a JavaFx OSGi bundle

I'm trying to run a JavaFx OSGi module, but I keep getting the error:
org.osgi.framework.BundleException: Unable to resolve OSGiDmHelloWorldProvider [7](R 7.0): missing requirement [OSGiDmHelloWorldProvider [7](R 7.0)] osgi.wiring.package; (osgi.wiring.package=javafx.application) Unresolved requirements: [[OSGiDmHelloWorldProvider [7](R 7.0)] osgi.wiring.package; (osgi.wiring.package=javafx.application)]
at org.apache.felix.framework.Felix.resolveBundleRevision(Felix.java:4112)
at org.apache.felix.framework.Felix.startBundle(Felix.java:2118)
at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:998)
at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:984)
This is how I load and start the modules:
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;
import org.osgi.framework.launch.Framework;
import org.osgi.framework.launch.FrameworkFactory;
import java.io.File;
import java.util.*;
public class Launcher {
private static String[] libs = null;
private BundleContext context;
private Launcher() {
FrameworkFactory frameworkFactory = ServiceLoader.load(FrameworkFactory.class).iterator().next();
Map<String, String> config = new HashMap<String, String>();
config.put("osgi.console", "");
config.put("osgi.clean", "true");
config.put("osgi.noShutdown", "true");
config.put("eclipse.ignoreApp", "true");
config.put("osgi.bundles.defaultStartLevel", "4");
config.put("osgi.configuration.area", "./configuration");
// automated bundles deployment
config.put("felix.fileinstall.dir", "./dropins");
config.put("felix.fileinstall.noInitialDelay", "true");
config.put("felix.fileinstall.start.level", "4");
config.put(Constants.FRAMEWORK_BOOTDELEGATION, "javafx.*,com.sun.javafx.*");
config.put(Constants.FRAMEWORK_BUNDLE_PARENT, Constants.FRAMEWORK_BUNDLE_PARENT_APP);
Framework framework = frameworkFactory.newFramework(config);
try {
framework.init();
framework.start();
} catch (BundleException e) {
e.printStackTrace();
}
context = framework.getBundleContext();
Bundle OSGiDmHelloWorldProvider = install("OSGiDmHelloWorldProvider");
try {
OSGiDmHelloWorldProvider.start();
} catch (BundleException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Launcher();
}
private String[] getLibs() {
if (libs == null) {
List<String> jarsList = new ArrayList<String>();
File pluginsDir = new File("libs");
System.out.println("PATHS : " + pluginsDir.getAbsolutePath());
for (String jar : pluginsDir.list()) {
jarsList.add(jar);
}
libs = jarsList.toArray(new String[jarsList.size()]);
}
return libs;
}
protected Bundle install(String name) {
String found = null;
for (String jar : getLibs()) {
if (jar.startsWith(name)) {
found = String.format("file:libs/%s", jar);
System.out.println(found);
break;
}
}
if (found == null) {
throw new RuntimeException(String.format("JAR for %s not found", name));
}
try {
return context.installBundle(found);
} catch (BundleException e) {
e.printStackTrace();
}
return null;
}
}
The OSGiDmHelloWorldProvider Activator class:
import com.bw.osgi.provider.able.HelloWorldService;
import com.bw.osgi.provider.impl.HelloWorldServiceImpl;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ProviderActivator implements BundleActivator {
Logger logger = LoggerFactory.getLogger(ProviderActivator.class);
Stage stage;
private ServiceRegistration registration;
BundleContext bundleContext;
#Override
public void start(BundleContext bundleContext) throws Exception {
registration = bundleContext.registerService(
HelloWorldService.class.getName(),
new HelloWorldServiceImpl(),
null);
Platform.runLater(new Runnable() {
#Override
public void run() {
stage = new Stage();
BorderPane pane = new BorderPane();
Scene scene = new Scene(pane, 400, 200);
pane.setCenter(new Label("This is a JavaFX Scene in a Stage"));
stage.setScene(scene);
stage.show();
}
});
System.out.println("STAGE CALLED !!!");
}
#Override
public void stop(BundleContext bundleContext) throws Exception {
registration.unregister();
logger.info("Set4Jfx Bundle: stop()");
Platform.runLater(new Runnable() {
#Override
public void run() {
stage.close();
}
});
}
}
How can I load a module that uses JavaFx in a Maven OSGi application?
The error message means that your bundle imports package javafx.application, and no bundle exports that package. Therefore the import cannot be resolved.
I note that in your launcher code you try to set bootdelegation to javafx.*. That might allow the class to be loaded from the boot classpath if your bundle ever got as far as running, however it cannot get that far because of the unresolved import.
If you intend for the JavaFX classes to be loaded from the boot classloader then you should remove the package import from your own bundle. You would also have to arrange for the JavaFX classes to actually be provided by the boot classloader, since AFAIK they are normally only visible from the extension classloader.
However a better solution would be leave the import alone, and arrange for the javafx.application package to be exported from a bundle. That could be done from the system bundle using Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA.
Update
You should probably look at the Drombler FX tool/framework from #Puce, since it sounds like he has already done a lot of these setup tasks. However I felt that his answer didn't directly address your question about why your code was failing.
I've released some first versions of Drombler FX - the modular application framework for JavaFX based on OSGi and Maven (POM first).
It takes care of initializing JavaFX and OSGi.
Maybe you find it useful. The application framework is Open Source and the code is available on GitHub.
There is also a tutorial with a Getting Started trail.

No suitable driver found in Vaadin project

Yes, it's that newbie to Vaadin, again. This time, I'm trying to see if I can do one of the most basic of tasks: connect to a database.
We use MS SQL Server here (version 2012, I believe) and we've been able to connect to it fine in two other Java programs that I've written. When attempting to do the same thing using a newly-created Vaadin project, however, I am told that No suitable driver found for jdbc:sqlserver://192.168.0.248;databaseName=job_orders_2014. I have checked and made sure that all three .jars from Microsoft are in the build path: sqljdbc.jar, sqljdbc4.jar, and sqljdbc41.jar.
Here's the ConnectionManager class that I've written which only tests whether or not it can get a connection:
package info.chrismcgee.sky.vaadinsqltest.dbutil;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.logging.Logger;
public class ConnectionManager {
Logger logger = Logger.getLogger(ConnectionManager.class.getName());
private static final String USERNAME = "web";
private static final String PASSWORD = "web";
private static final String CONN_STRING = "jdbc:sqlserver://192.168.0.248;databaseName=job_orders_2014";
public ConnectionManager() throws SQLException, ClassNotFoundException {
// Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
Connection conn = null;
try {
conn = DriverManager.getConnection(CONN_STRING, USERNAME, PASSWORD);
System.out.println("Connected!");
} catch (SQLException e) {
System.err.println(e);
} finally {
if (conn != null) {
conn.close();
}
}
}
}
The result is the SQLException message I mentioned earlier. I've tried it both with and without that Class.forName... line, which is apparently only necessary for Java versions below 7 (and we're using version 8). When that line is enabled, I get a ClassNotFoundException instead.
What gives?
EDIT 04/01/2015: To help clarify how this ConnectionManager class is called, I am simply creating an instance of it from the main class, thusly:
package info.chrismcgee.sky.vaadinsqltest;
import java.sql.SQLException;
import info.chrismcgee.sky.vaadinsqltest.dbutil.ConnectionManager;
import javax.servlet.annotation.WebServlet;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinServlet;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Label;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
#SuppressWarnings("serial")
#Theme("vaadinsqltest")
public class VaadinsqltestUI extends UI {
#WebServlet(value = "/*", asyncSupported = true)
#VaadinServletConfiguration(productionMode = false, ui = VaadinsqltestUI.class)
public static class Servlet extends VaadinServlet {
}
#Override
protected void init(VaadinRequest request) {
final VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
setContent(layout);
Button button = new Button("Click Me");
button.addClickListener(new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
try {
ConnectionManager connMan = new ConnectionManager();
} catch (SQLException | ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
layout.addComponent(new Label("Thank you for clicking"));
}
});
layout.addComponent(button);
}
}
You need your dependencies in your runtime environment.
Please have a look at this answer here at stackoverflow:
https://stackoverflow.com/a/19630339

NullPointerException upon starting my Bukkit plugin

I have been getting the following java.lang.NullPointerException when my plugin is being enabled. I don't really see the problem.
Error:
java.lang.NullPointerException
at tk.mypalsgaming.TARDIScraft.TARDIScraft.onDisable(TARDIScraft.java:31)
at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:219)
at org.bukkit.plugin.java.JavaPluginLoader.disablePlugin(JavaPluginLoader.java:481)
at org.bukkit.plugin.SimplePluginManager.disablePlugin(SimplePluginManager.java:401)
at org.bukkit.plugin.SimplePluginManager.disablePlugins(SimplePluginManager.java:394)
at org.bukkit.craftbukkit.v1_6_R2.CraftServer.disablePlugins(CraftServer.java:281)
at net.minecraft.server.v1_6_R2.MinecraftServer.stop(MinecraftServer.java:349)
at net.minecraft.server.v1_6_R2.MinecraftServer.run(MinecraftServer.java:445)
at net.minecraft.server.v1_6_R2.ThreadServerApplication.run(SourceFile:582)
plugin.yml:
name: TARDIScraft
main: tk.mypalsgaming.TARDIScraft.TARDIScraft
version: 0.0.1
depend: [Vault]
commands:
tardis:
description: TARDIS Command Block and Admin Command
usage: /<command> <TARDIS command> [parameters]
permission: TARDIScraft.admin
permission-message: You are not a TARDIS Admin, so you do not have access to this command.
TARDIScraft.java:
package tk.mypalsgaming.TARDIScraft;
import java.util.logging.Logger;
import net.milkbowl.vault.permission.Permission;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.RegisteredServiceProvider;
import org.bukkit.plugin.java.JavaPlugin;
public class TARDIScraft extends JavaPlugin {
Logger console = getLogger();
#Override
public void onEnable() {
console.info("Enabling the TARDIS plugin...");
// TODO: onEnable code
}
#Override
public void onDisable() {
console.info("Disabling the TARDIS plugin...");
// TODO: onDisable code
}
public static Permission permission = null;
#SuppressWarnings("unused")
private boolean setupPermissions()
{
RegisteredServiceProvider<Permission> permissionProvider = getServer().getServicesManager().getRegistration(net.milkbowl.vault.permission.Permission.class);
if (permissionProvider != null) {
permission = permissionProvider.getProvider();
}
return (permission != null);
}
public void onPlayerJoin(PlayerJoinEvent evt) {
Player player = evt.getPlayer();
if ( player.hasPermission("TARDIScraft.admin") ) {
console.info("Admin " + player.getName() + " has joined the game.");
}
}
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if ( cmd.getName().equalsIgnoreCase("tardis") ) {
boolean senderIsPlayer;
if ( sender instanceof Player ) {
senderIsPlayer = true;
} else senderIsPlayer = false;
// TODO: tardis Command
if ( args[0].equalsIgnoreCase("admin") ) {
Player playerToAdmin = Bukkit.getPlayer(args[1]);
if ( playerToAdmin != null ) {
permission.playerAdd(playerToAdmin, "TARDIScraft.admin");
}
}
return true;
} else {
return false;
}
}
}
The NullPointerException is from the "getLogger()" call. The parent class "JavaPlugin" has to have initialize() called before the logger exists. Since you are getting the logger at instantiation time rather than after initialize() is called, the parent class returns null.
The documentation suggested simply calling getLogger() inside your onEnable() and onDisable(), likely because initialize() has been called by then.
Note: The source code say to NOT call initialize() yourself!
See:
https://github.com/Bukkit/Bukkit/blob/master/src/main/java/org/bukkit/plugin/java/JavaPlugin.java#L246
http://wiki.bukkit.org/Plugin_Tutorial#Logging_a_message

eclipse plugin does not work after update to juno (eclipse 4)

I created an eclipse plugin that will hook into the save action to create a minified javascript file with the goolge closure compiler. See files below.
That worked until eclipse 3.7.2. Unfortunately now in eclipse 4.2.1 it seems that this creates an endless loop sometimes. The job "compile .min.js" (line 64 in ResourceChangedListener.java) seems the be the cause. It results in the case that the workspaced starts to build over and over. I guess this is because that job creates or changes a file triggering the workspace build again, which again triggers the job which triggers the build and so on.
But I can not figure out how to prevent this.
// Activator.java
package closure_compiler_save;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
/**
* The activator class controls the plug-in life cycle
*/
public class Activator extends AbstractUIPlugin {
// The plug-in ID
public static final String PLUGIN_ID = "closure-compiler-save"; //$NON-NLS-1$
// The shared instance
private static Activator plugin;
/**
* The constructor
*/
public Activator() {
}
#Override
public void start(BundleContext context) throws Exception {
super.start(context);
Activator.plugin = this;
ResourceChangedListener listener = new ResourceChangedListener();
ResourcesPlugin.getWorkspace().addResourceChangeListener(listener);
}
#Override
public void stop(BundleContext context) throws Exception {
Activator.plugin = null;
super.stop(context);
}
/**
* Returns the shared instance
*
* #return the shared instance
*/
public static Activator getDefault() {
return plugin;
}
}
// ResourceChangedListener.java
package closure_compiler_save;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
public class ResourceChangedListener implements IResourceChangeListener {
public void resourceChanged(IResourceChangeEvent event) {
if (event.getType() != IResourceChangeEvent.POST_CHANGE)
return;
IResourceDelta delta = event.getDelta();
try {
processDelta(delta);
} catch (CoreException e) {
e.printStackTrace();
}
}
// find out which class files were just built
private void processDelta(IResourceDelta delta) throws CoreException {
IResourceDelta[] kids = delta.getAffectedChildren();
for (IResourceDelta delta2 : kids) {
if (delta2.getAffectedChildren().length == 0) {
if (delta.getKind() != IResourceDelta.CHANGED)
return;
IResource res = delta2.getResource();
if (res.getType() == IResource.FILE && "js".equalsIgnoreCase(res.getFileExtension())) {
if (res.getName().contains("min"))
return;
compile(res);
}
}
processDelta(delta2);
}
}
private void compile(final IResource res) throws CoreException {
final IPath fullPath = res.getFullPath();
final IPath fullLocation = res.getLocation();
final String fileName = fullPath.lastSegment().toString();
final String outputFilename = fileName.substring(0, fileName.lastIndexOf(".")).concat(".min.js");
final String outputPath = fullPath.removeFirstSegments(1).removeLastSegments(1).toString();
final IProject project = res.getProject();
final IFile newFile = project.getFile(outputPath.concat("/".concat(outputFilename)));
Job compileJob = new Job("Compile .min.js") {
public IStatus run(IProgressMonitor monitor) {
byte[] bytes = null;
try {
bytes = CallCompiler.compile(fullLocation.toString(), CallCompiler.SIMPLE_OPTIMIZATION).getBytes();
InputStream source = new ByteArrayInputStream(bytes);
if (!newFile.exists()) {
newFile.create(source, IResource.NONE, null);
} else {
newFile.setContents(source, IResource.NONE, null);
}
} catch (IOException e) {
e.printStackTrace();
} catch (CoreException e) {
e.printStackTrace();
}
return Status.OK_STATUS;
}
};
compileJob.setRule(newFile.getProject()); // this will ensure that no two jobs are writing simultaneously on the same file
compileJob.schedule();
}
}
After I setup a blank eclipse classic environment, started a new eclipse plugin project there and recreated all files it works again partly.
In this environment starting a debug session I can save .js files and .min.js files are created automatically.
So far so good!
But when I install the plugin to my real developing eclipse environment automatic saving does not work.
At least one step further!
Step 2:
There were some files not included in the build obviously needed, like manifest. No idea why they were deselected.
Anyway it seems just setting up a blank eclipse 4 classic and going through the eclipse plugin wizard fixed my original problem. I still would love to know what was the actual problem...

Categories