33

CHow can I correctly provide the following functionally from C# in Java?

[C#]

#define PRODUCTION //Change from sandbox to production to switch between both systems.

#if SANDBOX
    using NetSuite.com.netsuite.sandbox.webservices;
#endif

#if PRODUCTION
    using NetSuite.com.netsuite.webservices;
#endif
2
  • 2
    Looks like I can't add an answer since the question's been closed, but I've read about a tool called Prebop (Disclaimer: I've not yet used it), that might do this and it apparently has support for Eclipse. (I agree with others though: in your situation, use DI. -- Just putting this here for other Googlers.) Commented Jul 1, 2015 at 17:37
  • see this answer, stackoverflow.com/a/48330157/3066295 Commented Sep 28, 2018 at 2:40

6 Answers 6

26

Java doesn't have a preprocessor - so the simple answer is that you can't.

This sort of thing is normally handled in Java using Dependency Injection - which is both more powerful and more flexible.

http://www.vogella.com/articles/DependencyInjection/article.html

Sign up to request clarification or add additional context in comments.

3 Comments

It should be noted that, in the OP's given example, he should also be using DI/IoC in C# anyway -- it's basically a bad example -- I think the question is still valid though, and this answer, while valid for the OP's scenario is kind of disappointing -- (not your fault @TimB, though the answer below about using cpp is kind of interesting...)
I strongly disagree that DI is "more flexible and more powerful." A jpp analogue to cpp similarly would allow for textual substitutions which can aid dramatically in the readability of repeated expressions where you simply don't want a method call, among many things. Not including it in the language started as a silly argument of potential abuse and remains so. Java has many valid arguments regarding abuse (e.g., disallowing MI, not including operator overloading, etc.), but this was one place were I believe they botched it. Thankfully, C# didn't follow in those particular footsteps.
I came from C, I used to use the pre-processor all the time. I've not found anything in decades of using Java where I've needed the pre-processor. There's always a cleaner way. Particularly with things like Cucumber available for when you need a less code-focussed approach
10

Java doesn't have a preprocessor, yet that doesn't mean that you can't run Java code through cpp - though it would not be supported by any tools, AFAIK.

1 Comment

Looks like I can't add an answer since the question's been closed, but I've read about a tool called Prebop (Disclaimer: I've not yet used it), that might do this and it apparently has support for Eclipse. (I agree with others though: in the OP's situation, he should use DI. -- Just putting this here for other Googlers.)
1

Use Dependency Injection/Inversion of Control. Depending on your actual needs, you might be able to get away with something as simple as property file/environment variables to control things.

You might be able to use static defines around some types of initialization/code.

3 Comments

Using the example in the post, how would DI/IoC help? From what I've read (albeit briefly) it appears that DI is mostly used for decoupling and not conditional compilation. My specific use case surrounds changing import statements en mass in order to connect to a sandbox vs production system. Is there a specific tutorial/set of docs I should read?
DI/IoC is "conditional compilation" at run time. Without knowing what you're actually trying to swap in and out, I'm guessing, but you'd use one of two webservice implementations, e.g., in development, they'd all be stubbed out to return known values. This is often done for testing purposes, for example. It's more likely we'd use different connection parameters/endpoints in development, which is generally just config values, which wouldn't require DI.
A solution would be to use the same namespace for both versions, putting each version in its own JAR archive and just loading the appropriate one.
1

You can use something based on <#FreeMarker>.

enter image description here

source: https://github.com/mkowsiak/jpp

However, this solution will require pre-compilation step, if you want to change the code. On the other hand, you can still create code that works without pre-processing steps - sort of "default" compilation.

Comments

1

I'm using java-comment-preprocessor. It is very easy and convenient and provides also integration for Maven, Ant and Gradle. It is using Java comments and a preprocessor is used generating the actual code based on the preprocessor flags, e.g.:

//#if simulator
private final static int FOO = 2;
//#else
private final static int FOO = 1;
//#endif

Maven integration:

<plugin>
                <groupId>com.igormaznitsa</groupId>
                <artifactId>jcp</artifactId>
                <version>7.0.5</version>
                <executions>
                    <execution>
                        <id>preprocessSources</id>
                        <phase>process-sources</phase>
                        <goals>
                            <goal>preprocess</goal>
                        </goals>
                        <configuration>
                            <vars>
                                <simulator>${simulator}</simulator>
                            </vars>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

1 Comment

This worked for me. There are literally ZERO examples for jcp, beyond what is shown right here. And the documentation is diffuse. Some of what I found: the changelog github.com/raydac/java-comment-preprocessor/blob/master/… says that v7.2.0 of jcp requires jdk11, prior to 7.2.0, it works with jdk8. I had to scan the source code of the jcp maven plugin github.com/raydac/java-comment-preprocessor/blob/master/jcp/src/… to determine what options I could use. It's a walk through a dark foggy forest.
0

Adding to the answer by k_o_ I used the java-comment-preprocessor (jcp), and this is how my maven plugins looked:

      <!-- this plugin processes the source code and puts the 
           processed files into ${project.build.directory}/generated-test-sources/preprocessed -->
      <plugin>
        <groupId>com.igormaznitsa</groupId>
        <artifactId>jcp</artifactId>
        <!-- 7.2.0 is latest at this time, but 7.1.2 is latest that works 
             with jdk8. -->
        <version>7.1.2</version>
        <executions>
          <execution>
            <!-- Only my test source has conditionals.
                 Use generate-sources if using "main". --> 
            <phase>generate-test-sources</phase>
            <goals>
              <goal>preprocess</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <!-- not sure why , but I believe this is necessary when using
               generate-test-sources -->
          <useTestSources>true</useTestSources>
          <vars>
            <JDK11>true</JDK11>
          </vars>
          <sources>
            <source>${project.basedir}/src/test/java-unprocessed</source>
          </sources>
          <!-- I think I can use <targetTest> to specify where the processed files
               should be written. I just accepted the default. -->  
        </configuration>
      </plugin>

      <plugin>
        <!-- This plugin adds the generated (preprocessed) code from above, 
             into the build -->
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>build-helper-maven-plugin</artifactId>
        <version>3.5.0</version>
        <executions>
          <execution>
            <id>add-source</id>
            <phase>generate-test-sources</phase>
            <goals>
              <!-- Use add-source for "main". I think you need two different
                   execution entries if you need both phases.  -->
              <goal>add-test-source</goal>
            </goals>
            <configuration>
              <sources>
                <!-- This is the default output from the above jcp plugin -->
                <source>${project.build.directory}/generated-test-sources/preprocessed</source>
              </sources>
            </configuration>
          </execution>
        </executions>
      </plugin>

The result is, Java code files that are found in ${project.basedir}/src/test/java-unprocessed are processed by JCP and then dropped into ${project.build.directory}/generated-test-sources/preprocessed, and then the regular test compile includes those generated test sources.

My Java code has stuff like this in it:

//#ifdef JDK11
  code code code
//#endif
//#ifdef JDK8
  code code code
//#endif

And it does what you think it should do.

The jcp plugin is really handy, and confoundingly undocumented. There's literally no documentation, no public examples, no hints. The so-called "examples" on the wiki are not examples at all. They don't show how to do this ^^. Also I could not find a reference on all the expressions that are supported in comments. All I used was #ifdef. There's a bunch more. Good luck figuring out what's available!

For information on how to use it, I guess....read the source code?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.