Java equivalent of #ifdef that allows non-compilable code - java

Is it possible in Java to do a sort of #ifdef thing, like in C/C++?
Example:
class Test
{
public static final boolean ANDROID = false;
public Test()
{
if (ANDROID)
{
// do stuff that won't compile if not on android
}
else
{
// do stuff that should be only done on desktop
}
}
}
Note that even if ANDROID is false, as in the example, it will still try to compile the code inside of the if, even though it won't (and shouldn't) compile.
I'm looking for a way to do conditional compilation -- the compiler shouldn't even look at the if if ANDROID is false.
The context of my question is that I have a Processing application in Eclipse. I'm using both normal Processing and Processing for Android in two separate projects, but I want to be able to move the source code of the projects between one another without having compiler errors. For example, I want to be able to have source code files that I can move from the Android project to the desktop project and only have to change a couple of things -- for example, changing ANDROID = true to ANDROID = false.
I really need it to be conditional compilation because when I copy the source code from the Android project to the desktop project, the desktop libraries obviously won't include Android libraries, and then the source code won't even compile.
EDIT: So now that I know that there is no preprocessor in Java, my question is: is there any other way to have this functionality in my projects (being able to copy source code from one to the other with only very minor changes) without having to manually [un]comment specific pieces of code and having to remember where those are?
EDIT 2: This is not a duplicate of the other question because my question includes code that may have compiler errors in it, whereas the question that this was closed as a duplicate of does not. (That other question concerns only code that would compile fine even without #ifdefs.) To explain, the most highly rated (and accepted) answer for the other question talks about code that is compiled, but is simply not emitted in the bytecode. However, my question concerns code that would not even compile originally.

As others have said, the answer to your actual question is no.
However, you might approach your problem by isolating the Android or desktop code. You could do this by having three separate projects in eclipse:
Core: This is the "shared" code that exists between both versions.
Android: This contains only the code that runs on Android.
Desktop: This contains only the code that runs on desktop.
Both your Android and Desktop projects would contain the Core project on their classpaths. In eclipse, you'd do this by going to your Java Build Path, then clicking the Projects tab, then adding the Core project to the "Required projects" list.
Then you'd set your code up so your Android and Desktop projects are what you actually deploy, and your Core project contains the code shared between them. Here's a simple example. Let's say we have an example class that looks like this:
public class Adder{
public void addAndPrint(int x, int y){
//code that will work on both Android and desktop
int sum = x+y;
if (ANDROID){
//code that will only work on Android
Log.v("example", "Sum:" + sum);
}
else{
//code that will only work on desktop
System.out.println("Sum: " + sum)
}
}
}
You could get around this by refactoring your code to isolate the "core" code that will work on both desktop and Android. Something like this:
//example core class
public class CoreAdder{
Printer printer;
public CoreAdder(Printer printer){
this.printer = printer;
}
public void addAndPrint(int x, int y){
int sum = x+y;
printer.print("Sum: " + sum);
}
}
//example core interface. We might print differently on
//Android and Desktop, so implement this interface in each.
public interface Printer{
public void print(String printMe);
}
Then, you'd isolate the code that will only work on Desktop:
//on desktop, use System.out.println()
public class DesktopPrinter implements Printer{
public void print(String printMe){
System.out.println(printMe);
}
}
//on desktop, entry point is main()
public class DesktopMain{
public static void main(String... args){
DesktopPrinter printer = new DesktopPrinter();
CoreAdder adder = new CoreAdder(printer);
adder.addAndPrint(1, 2);
}
}
And the code that will only work on Android:
//on Android, use a logger
public class AndroidPrinter implements Printer{
public void print(String printMe){
Log.v("example", "index=" + i);
}
}
//on Android, entry point is Activity
public class AndroidActivity extends Activity{
public void onCreate(Bundle savedInstanceState) {
AndroidPrinter printer = new AndroidPrinter ();
CoreAdder adder = new CoreAdder(printer);
adder.addAndPrint(1, 2);
}
}
Note that this is just an example, and I know that both System.out.println() and Log.v() could work on either platform. But the idea is the same: split your project up into multiple projects, and use interfaces to abstract away the behavior that changes between platforms.

As Java does not natively include a preprocessor, it would be incumbent upon you to manually execute one before compiling. The c preprocessor is m4, which you can run yourself.

There are no-preprocessors in java like C,C++ etc. All you can do is comment out the code.

Use #ifdef and friends as in C and run the Java sources through the C pre-processor before compiling them.
For gcc the pre-processor is called cpp, for VC it's cl.exe using the option /P.

No, there is no such thing as a preprocessor in Java that can hide chunks of code to the JVM.
EDIT:
While you could of course run any program against your code base to preprocess it, think about if you really want this. The Android code will diverge more from the other Java code in time and your code will be littered with those #ifdef-like statements. Your IDE will also still see them and give you errors in both areas of code. In this case it's much easier to just make two projects out of it or, and that's my advice, create a platform independent library which you include in both projects and includes the functionality you need.

By defining productFlavors in build you can use folders that will be compiled when specific flavor is chosen thus you can make code in same codebase available conditionally at compile time.

Related

Errors when trying to create Xamarin Android binding Java Library for mapsforge/vtm

I have tried to use the Java map library mapsforge-vtm to show an offline map using a mapsforge file with Xamarin Android.
Within Visual Studio 2019, I created one aar binding project as "LibraryProjectZip" for the file "vtm-android-0.13.0.aar" and one jar binding project as "EmbeddedJar" for the file "vtm-android-0.13.0.jar".
There is also a dependency to "vtm-0.13.0.jar" which you can see in the file "vtm-android-0.13.0.pom".
That "vtm-0.13.0.jar" file seems to cause the problems (e.g. the java interface Gesture which I include further down below).
If you keep following the dependencies (by looking in the pom files), there are also dependencies to "slf4j-api-1.7.28.jar" and "androidsvg-1.4.jar" but those two jars do not seem to cause problems, as far as I can tell.
Regarding the problem file "vtm-0.13.0.jar" I have tried to use it as an "EmbeddedReferenceJar" within both of the above mentioned projects (i.e. the aar binding and the jar binding projects for vtm-android).
Both of those two binding projects can build without errors (when also using "androidsvg-1.4.jar" and "slf4j-api-1.7.28.jar" as "EmbeddedReferenceJar"'s)
However, when trying to reference those projects from a Xamarin Android app, it does not work.
When trying to do that, I can not reference both the aar binding and the jar binding projects because then there is an error message about duplicated versions of for example the class "Org.Oscim.Android.MapView".
But when I use only one of them (i.e. either aar or jar project), then only the types from the main libraries are available (i.e. the "LibraryProjectZip" file for "vtm-android-0.13.0.aar" and "EmbeddedJar" file for "vtm-android-0.13.0.jar").
But I seem to NOT be able to reference any types from the "EmbeddedReferenceJar".
For example, there is a java type "org.oscim.tiling.source.mapfile.MapFileTileSource" in the "vtm-0.13.0.jar" but it does not seem to become available i.e. I can NOT use:
using Org.Oscim.Tiling.Source.Mapfile.MapFileTileSource;
In fact, the only namespace I can use, starting with "Org.Oscim" is "Org.Oscim.Android" e.g. this works:
using Org.Oscim.Android;
Then I tried to create a separate "EmbeddedJar" from the file "vtm-0.13.0.jar", since I was hoping that it then could be referenced from Visual Studio.
(and in that project I added "slf4j-api-1.7.28.jar" as "EmbeddedReferenceJar")
However, the compilation failed with 85 errors.
And I have tried all four combinations of settings for "Android Class Parser" and "Android Codegen Target"
(i.e. the four combinations of "class-parse + XAJavaInterop1" and "jar2xml + XAJavaInterop1" and "class-parse + XamarinAndroid" and "jar2xml + XamarinAndroid")
I have also tried with a couple of different target frameworks (Android 4.4 and Android 9 and Android 10).
50 of those 85 errors are this same error:
Error CS0234 The type or namespace name 'IGesture' does not exist in the namespace 'Org.Oscim.Event' (are you missing an assembly reference?)
vtm-jar ...\obj\Debug\generated\src\Org.Oscim.Event.IGesture.cs
Indeed, when looking in that file "IGesture.cs" there is no interface defined there.
I had expected to find something like "public partial interface IGesture ..." in that file, in a similar way as there is a "public partial interface IGestureListener ..." in the file "IGestureListener.cs" in the same directory.
I suspect that it has something to do with the fact that the java interface "Gesture" seems to be a bit unusal and thus not being nicely supported by Xamarin/Visual Studio.
This is what I am talking about:
Here is a "normal" kind of Java interface (GestureListener) which seems to work without errors in Visual Studio:
https://github.com/mapsforge/vtm/blob/master/vtm/src/org/oscim/event/GestureListener.java
package org.oscim.event;
public interface GestureListener {
boolean onGesture(Gesture g, MotionEvent e);
}
Here is the source code for the problematic interface (Gesture) in "vtm-0.13.0.jar":
https://github.com/mapsforge/vtm/blob/master/vtm/src/org/oscim/event/Gesture.java
package org.oscim.event;
public interface Gesture {
final class Press implements Gesture {
}
final class LongPress implements Gesture {
}
final class Tap implements Gesture {
}
final class DoubleTap implements Gesture {
}
final class TripleTap implements Gesture {
}
final class TwoFingerTap implements Gesture {
}
Gesture PRESS = new Press();
Gesture LONG_PRESS = new LongPress();
Gesture TAP = new Tap();
Gesture DOUBLE_TAP = new DoubleTap();
Gesture TRIPLE_TAP = new TripleTap();
Gesture TWO_FINGER_TAP = new TwoFingerTap();
}
As far as I can remember, I do not think I have ever seen that kind of Java code with classes being defined and instantiated within an interface.
And I suppose that Xamarin/Visual Studio also have a hard time to understand that kind of Java code.
So, is there anything you can do about this (and all other build errors, totally 85, with this vtm library)?
Has anyone been able to implement an Android App with Xamarin Android that uses mapsforge-vtm bindings, including also having been able to put all the pieces together and succeeded to display a map from a mapsforge map file?

Modifying react-native files

i changed a BaseViewManager.java file inside of react-native to make resource-id available thru react-native. the thing is that no matter what i do, nothing takes effect, even if i put typos in the .java files. my colleague told me it's probably because the .java is not being built.
so how to build the react-native .java files??
i tried npm start of course but nothing took any effect.
and this is the code that i want to change
#ReactProp(name = PROP_TEST_ID)
public void setTestId(T view, String testId) {
view.setTag(R.id.react_test_id, testId);
// temporarily set the tag and keyed tags to avoid end to end test regressions
view.setTag(testId);
}
#ReactProp(name = PROP_NATIVE_ID)
public void setNativeId(T view, String nativeId) {
view.setTag(R.id.view_tag_native_id, nativeId);
ReactFindViewUtil.notifyViewRendered(view);
}
You have to build React Native from source. Here is tutorial for that: https://reactnative.dev/contributing/how-to-build-from-source I tried it and it works :)

Making program extensions

I am making a program for computer surveillance at the moment.
It's for a competition in my country Croatia(InfoKup).
I have several options for sending command to another PC, but I
want to make the possibility for the command extension for people
who know Java. So I want to make the user be able to add some of his
custom commands for the program. For example something like
Minecraft mods. I know it is possible, but how would I go about
doing that.
Any help would be greatly appreciated. My code on GitHub:GitHub
Don't mind the stream thing.
It's something my friend is experimenting with.
EDIT: e.g.
Currently I have the possibility to send popups to another PC. What if the extension maker knew the code to send cmd commands and wants to add that function. He makes an extension and puts it in the extension folder. Voila we have a new possibility.
EDIT 2:
Don't be so harsh on me pls :). Thx for the dynamic class loading tip. I have been looking into that, and it looks promising.
Basically what I want to have possible is the user to drop the "mod/extension/whatever" in the "mod/extension/whatever" folder, and the program would load it and put all of the buttons declared in the class in to the GUI, and with them the function. I think I'm getting the hang of this, but any tips would be helpful.
e.g.
package sth.sth;
import blah.blah.*;
public class ClassSTH extends SchoolarButton{
public ClassSTH(String params){
super(params);
}
#Override
public void OnClick(){
doStuff();
}
}
EDIT:
The problem is easily solvable using Java Reflection! I wish someone posted that as an answer befpre blatanty downvoting a question because pf a GitHub link that was there to prpve that I've actually done something.
This kind of thing can be accomplished by using Java Reflection!
How to load and invoke a method on an external jar:
File f = new File("plugin.jar");
URLClassLoader cl = new URLClassLoader(new URL[]{f.toURI().toURL(), null});
Class<?> clazz = cl.loadClass("epicurus.Client");
Method main = clazz.getMethod("main", String[].class);
main.invoke(null, new Object[]{new String[]{}});

Eclipse RCP: Custom console

I am trying to create a console that would work as a shell for a custom programming language. It would be very similar to the pydev interactive console.
Currently, my RCP uses the basic TextConsole and is connected to the shell via pipes so it just displays whatever the shell displays and if the user enters anything in the RCP console, the same is written in the shell.
I want to be able to do a bit more such as move the caret position, add events for up and down arrow keys etc. I believe to do that I need to add a StyledText widget to the console which is done via the ConsoleViewer.
So my question is, that is there any way for me to either override the TextConsole's ConsoleViewer or if I were to extend TextConsole and create my own, then how do I link it with the launch configuration (the one that connects the shell via pipes)?
Also, to get the current default console I use DebugUITools.getConsole(process).
I'm sorry if I haven't put all the information needed; it is a bit difficult to explain. I am happy to add more information.
An idea...
From what I understand I can create a TextConsolePage from the TextConsole using createPage(ConsoleView). Once I have the page I can set the viewer via setViewer(viewer). Here I thought if I create my own viewer (which will have the appropriate stylewidget) then that could be a lead. The only problem is that the viewer needs a Composite and I can't seem to figure out where to get that from.
Why don't you just follow what PyDev does (if you're able to cope with the EPL license)?
The relevant code may be found at:
https://github.com/aptana/Pydev/tree/ad4fd3512c899b73264e4ee981be0c4b69ed5b27/plugins/org.python.pydev/src_dltk_console
https://github.com/aptana/Pydev/tree/ad4fd3512c899b73264e4ee981be0c4b69ed5b27/plugins/org.python.pydev.debug/src_console
So I thought I would answer this myself as I was finally able to accomplish the console. It still is a working prototype but I guess as you keep adding things, you can clean up the code more and more. For my current purposes this is how it worked.
If you want the short version, then I basically mimicked the ProcessConsole provided by Eclipse as that is what I needed: a console in which I can connect a process but since the ProcessConsole is internal, I like to avoid extending those classes.
Following is an outline of the classes I used to achieve interaction with my console. I am not going to give the pretext as to where MyConsole was created. Basically, instead of using DebugUITools.getConsole(myProcess), I used my own myProcess.getConsole() method. MyProcess extends RuntimeProcess.
class MyConsole extends IOConsole {
private IOConsoleInputStream fInput;
private IOConsoleOutputStream fOutput;
private IStreamsProxy fStreamsProxy;
private ConsoleHistory history;
//This is to remember the caret position after the prompt
private int caretAtPrompt;
/* in the console so when you need to replace the command on up and down
* arrow keys you have the position.
* I just did a caretAtPrompt += String.Length wherever string was
* appended to the console. Mainly in the streamlistener and
* InputJob unless you specifically output something to the output
* stream.
*/
//In the constructor you assign all the above fields. Below are some
//to point out.
//fInput = getInputStream();
// fStreamsProxy = process.getStreamsProxy();
// fOutput = newOutputStream();
//We must override the following method to get access to the caret
#Override
public IPageBookViewPage createPage(IConsoleView view) {
return new MyConsolePage(this, view);
}
//After this I followed the ProcessConsole and added the
//InputJob and StreamListener
//defined in there.
}
class MyConsolePage extends TextConsolePage {
//Not much in this class, just override the createViewer
// to return MyConsoleViewer
}
class MyConsoleViewer extends TextConsoleViewer {
//This is the most important class and most of the work is done here
//Again I basically copied everything from IOConsoleViewer and then
//updated whatever I needed
//I added a VerifyKeyListener for the up and down arrow
//keys for the console history
MyConsoleViewer (Composite parent, MyConsole console) {
//I have omitted a lot of code as it was too much to put up,
//just highlighted a few
getTextWidget().addVerifyKeyListener(new MyKeyChecker());
}
class MyKeyChecker implements VerifyKeyListener {...}
}
This is the code for ProcessConsole.
This is the code for IOConsoleViewer.
The ConsoleHistory class I created just had a doubly linked string list to save all the commands the user entered. Quite a simple class to create.
Once you look at the Eclipse classes (ProcessConsole and IOConsoleViewer) it is actually all quite self explanatory. I haven't put in much code here because there is quite a bit. But hopefully this gives some direction as I was completely lost when I started.
I am happy to answer questions though and add more specific code if anyone asks.

In order to Macify a Java app, to catch the about event, do I have to implement a menu?

The macify Notepad example is the only example of 'macification' I could find, and it's all fine and dandy I guess, apart from the menu which completely screws up my layout.
I'm very, very new at Java so I follow examples like these to the letter, but this menu really has to go.
Is there a way to catch the 'about' stuff without a menu? After all, this about thing on Mac OSes seems to be there even without one. Standard procedure, etc.
I don't have a Mac to test the code, so trial and error is severely limited...
How is this done?
Bit of a necro-post but it's code I use all the time. It's complicated and uses reflection to avoid throwing errors on non-Mac systems, however.
In the initialization of your app or as a static code block:
if (System.getProperty("os.name").contains("Mac")) {
try {
Object app = Class.forName("com.apple.eawt.Application")
.getMethod("getApplication")
.invoke(null);
Object al = Proxy.newProxyInstance(
Class.forName("com.apple.eawt.AboutHandler").getClassLoader(),
new Class[]{Class.forName("com.apple.eawt.AboutHandler")},
new AboutListener()
);
app.getClass()
.getMethod("setAboutHandler", Class.forName("com.apple.eawt.AboutHandler"))
.invoke(app, al);
}
catch (Exception e) {
//fail quietly
}
}
At the bottom of the source file after the last curly brace
public class AboutListener implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) {
//Show About Dialog
return null;
}
}
When releasing a full application in java things like this make nice small touches. This should be mostly copy-and-paste-able but you will need to add a line or two to display an about box. If you need to test really badly use web-start, dropbox public links, and a neighborhood Apple Store.

Categories

Resources