j2objc-contrib / j2objc-gradle

This plugin is no longer actively maintained. J2ObjC Gradle Plugin: enables Java source to be part of an iOS application's build so you can write an app's non-UI code (such as application logic and data models) in Java, which is then shared by Android apps (natively Java) and iOS apps (using J2ObjC), all as part of your usual Android Gradle build.
https://github.com/j2objc-contrib/j2objc-gradle
Apache License 2.0
139 stars 43 forks source link

Custom dependencies #12

Closed PaNaVTEC closed 9 years ago

PaNaVTEC commented 9 years ago

Hi Bruno, I'm trying to use the plugin but i find I need something more, in my case I have 2 modules: presentation and domain, Presentation depends on domain so I have in my build.gradle on presentation:

j2objcConfig {
    j2objcHome parent.ext.j2objcPath
    destDir iOsProjectPath + 'Presentation'
    testExecutedCheck false
}

But when I try to execute j2objcCopy it just crashes because does not find something of the classes that are on domain, I think I need to configure the classpath but there is no option to configure "j2objcConfig" with this, any hints?

Thanks.

brunobowden commented 9 years ago

I'm trying to understand this...

What error message do you see? Anything else helpful with --info? What domain? What classes is it looking for?

On Thu Feb 12 2015 at 12:16:38 PM Christian Panadero < notifications@github.com> wrote:

Hi Bruno, I'm trying to use the plugin but i find I need something more, in my case I have 2 modules: presentation and domain, Presentation depends on domain so I have in my build.gradle on presentation:

j2objcConfig { j2objcHome parent.ext.j2objcPath destDir iOsProjectPath + 'Presentation' testExecutedCheck false }``` But when I try to execute j2objcCopy it just crashes because does not find something of the classes that are on domain, I think I need to configure the classpath but there is no option to configure "j2objcConfig" with this, any hints? Thanks.

— Reply to this email directly or view it on GitHub https://github.com/brunobowden/j2objc-gradle/issues/12.

brunobowden commented 9 years ago

If the module uses a java plugin, it depends on "test" and if there's an android plugin, it depends on "assemble". See the lines here:

https://github.com/brunobowden/j2objc-gradle/blob/master/j2objc.gradle#L640

        // Make sure the wider project builds successfully
        if (project.plugins.findPlugin('java')) {

project.tasks.findByName('j2objcCycleFinder').dependsOn('test') } else if (project.plugins.findPlugin('com.android.application')) {

project.tasks.findByName('j2objcCycleFinder').dependsOn('assemble') } else { def message = "j2objc plugin didn't find either 'java' or 'com.android.application'\n" + "plugin (which was expected). When this is found, the j2objc plugin\n" + "will build and run that first to make sure the project builds correctly.\n" "This will not be done here as it can't be found." println message }

On Thu Feb 12 2015 at 12:50:03 PM Bruno wrote:

I'm trying to understand this...

What error message do you see? Anything else helpful with --info? What domain? What classes is it looking for?

On Thu Feb 12 2015 at 12:16:38 PM Christian Panadero < notifications@github.com> wrote:

Hi Bruno, I'm trying to use the plugin but i find I need something more, in my case I have 2 modules: presentation and domain, Presentation depends on domain so I have in my build.gradle on presentation:

j2objcConfig { j2objcHome parent.ext.j2objcPath destDir iOsProjectPath + 'Presentation' testExecutedCheck false }``` But when I try to execute j2objcCopy it just crashes because does not find something of the classes that are on domain, I think I need to configure the classpath but there is no option to configure "j2objcConfig" with this, any hints? Thanks.

— Reply to this email directly or view it on GitHub https://github.com/brunobowden/j2objc-gradle/issues/12.

PaNaVTEC commented 9 years ago

Both projects are java Presentation depends on Domain and uses classes of the domain module,

presentation.build:

dependencies {
    compile project(':domain')
}

I fix it as a temporary workarround adding a custom classpath arg to j2objc: /Users/panavtec/Documents/panavtecWorkspace/BBcleancontacts/domain/build/libs/domain.jar

I don't know if im explaining my problem well...

brunobowden commented 9 years ago

I think I understand now. What you need to do ischange the code that assembles the dependencies. At the moment, it will just collect the j2objc jar's. You also need to add the other jar's.

The following code is used in the cycleFinder and translate tasks and need the extra jar's:

            project.j2objcConfig.translateJ2objcLibs.each { library ->
                def libPath = J2objcUtils.j2objcHome(getProject()) +

"/lib/" + library args "-classpath", project.file(libPath).path }

I'm not sure what happens for the translate phase. I believe you may need to translate and compile the dependency, then add it as a Xcode dependency, like the j2objc -ljre_emul library.

On Thu Feb 12 2015 at 1:01:19 PM Christian Panadero < notifications@github.com> wrote:

Both projects are java Presentation depends on Domain and uses classes of the domain module,

presentation.build:

dependencies { compile project(':domain') }

I fix it as a temporary workarround adding a custom classpath arg to j2objc: /Users/panavtec/Documents/panavtecWorkspace/BBcleancontacts/domain/build/ libs/domain.jar

I don't know if im explaining my problem well...

— Reply to this email directly or view it on GitHub https://github.com/brunobowden/j2objc-gradle/issues/12#issuecomment-74151871 .

PaNaVTEC commented 9 years ago

I modified this section to add a custom .jar to the classpath but now i have other problem, when I try to execut j2objcCopy it crashes with:

Error:/projectpath/presentation/build/j2objc/MainPresenter.m:6:10: fatal error: 'EventBus.h' file not found
#include "EventBus.h"
         ^
1 error generated.
FAILURE: Build failed with an exception.

* Where:
Script '/Users/panavtec/Documents/panavtecWorkspace/BBcleancontacts/j2objc.gradle' line: 447

* What went wrong:
Execution failed for task ':presentation:j2objcCompile'.
> Process 'command '/Users/panavtec/Documents/panavtecWorkspace/iOSCleanContacts/j2objc-dist/j2objcc'' finished with non-zero exit value 1

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

Eventbus is a Java interface and is on domain.jar this happens when I try to execute j2objcCopy in presentation module. So, how I link this 2 modules?

brunobowden commented 9 years ago

Hi Christian, I'm busy with meetings today and tomorrow. I'll respond on Saturday. Feel free to ask on the j2objc-discuss list if you like.

My suggestion is run the gradle task with "--info" to see what the output is... then try that same command again replacing j2objc with javac - they use the same command line flags.

On Thu Feb 12 2015 at 2:06:04 PM Christian Panadero < notifications@github.com> wrote:

I modified this section to add a custom .jar to the classpath but now i have other problem, when I try to execut j2objcCopy it crashes with:

Error:/projectpath/presentation/build/j2objc/MainPresenter.m:6:10: fatal error: 'EventBus.h' file not found

include "EventBus.h"

     ^1 error generated.FAILURE: Build failed with an exception.
  • Where:Script '/Users/panavtec/Documents/panavtecWorkspace/BBcleancontacts/j2objc.gradle' line: 447
  • What went wrong:Execution failed for task ':presentation:j2objcCompile'.> Process 'command '/Users/panavtec/Documents/panavtecWorkspace/iOSCleanContacts/j2objc-dist/j2objcc'' finished with non-zero exit value 1
  • Try:Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

Eventbus is a Java interface and is on domain.jar this happens when I try to execute j2objcCopy in presentation module. So, how I link this 2 modules?

— Reply to this email directly or view it on GitHub https://github.com/brunobowden/j2objc-gradle/issues/12#issuecomment-74163325 .

yissachar commented 9 years ago

Hi @brunobowden, I am also trying to have the plugin translate dependencies. I want all compile dependencies to be translated with j2objc.

With your hint above regarding the classpath, I was able to get as far as @PaNaVTEC - j2objc successfully translates my source files. However, it does not translate the dependencies themselves, so my the translated files will not compile.

In my case, I am using Jackson, so for instance in one of my translated files I will have an #include "ObjectMapper.h". But since ObjectMapper was never translated by j2objc it will obviously not compile.

How can I modify the plugin to have the dependency files also be translated?

Here is what I have so far:

project.configurations.compile.each { file ->
    args "-classpath", file.path
}
brunobowden commented 9 years ago

j2objc can only translate source code and not compiled libraries

@TomBall has already shared some advice on building Jackson: https://groups.google.com/d/msg/j2objc-discuss/0Dv82EccLmA/pHTYN82Wu-0J

On Wed, Apr 1, 2015 at 9:55 AM yissachar notifications@github.com wrote:

Hi @brunobowden https://github.com/brunobowden, I am also trying to have the plugin translate dependencies. I want all compile dependencies to be translated with j2objc.

With your hint above regarding the classpath, I was able to get as far as @PaNaVTEC https://github.com/PaNaVTEC - j2objc successfully translates my source files. However, it does not translate the dependencies themselves, so my the translated files will not compile.

In my case, I am using Jackson, so for instance in one of my translated files I will have an #include "ObjectMapper.h". But since ObjectMapper was never translated by j2objc it will obviously not compile.

How can I modify the plugin to have the dependency files also be translated?

Here is what I have so far:

project.configurations.compile.each { file -> args "-classpath", file.path }

— Reply to this email directly or view it on GitHub https://github.com/brunobowden/j2objc-gradle/issues/12#issuecomment-88540244 .

yissachar commented 9 years ago

I ended up using GSON instead, but the same approach - I translated the library sources separately and added it. Thanks for the plugin, it works great.

confile commented 9 years ago

@yissachar How did you use GSON? Did you include the jar and translated it together?

yissachar commented 9 years ago

No, I ran j2objc manually on the GSON sources separately and then added them to Xcode. Then I used this Gradle plugin with my modification from above to translate my own source files and added them to Xcode. GSON is specified as a compile dependency in my Gradle file.

On Fri, Apr 3, 2015, 1:59 PM Confile notifications@github.com wrote:

@yissachar https://github.com/yissachar How did you use GSON? Did you include the jar and translated it together?

Reply to this email directly or view it on GitHub https://github.com/brunobowden/j2objc-gradle/issues/12#issuecomment-89376317 .

advayDev1 commented 9 years ago

Here's how I got this working:

If I have:

dependencies {
    compile project(':other-project')
    compile project(':other-project2')
}

Then I add this to the j2objcConfig:

j2objcConfig {
...
    translateSourcepaths = "${projectDir}/../other-project/src/main/java:${projectDir}/../other-project2/src/main/java"
    translateFlags = "--build-closure"
}

This causes j2objc to additionally generate just the objc files needed from those other project's source directories as well. Now to figure out how to generate translateSourepaths from all project dependencies...

(completely new to j2objc and gradle btw, so this is guessing and checking)

confile commented 9 years ago

You can also the translateSourcepaths property from this plugin.

See: https://github.com/brunobowden/j2objc-gradle/blob/master/j2objc.gradle#L134

It translated all needed source files from source jars which where added to the sourcepath by the plugin.

The problem is that j2objc seems to have some problems with inner classes and inner types. As reported by this issue: https://github.com/google/j2objc/issues/513

advayDev1 commented 9 years ago

I think that's exactly what I'm doing (?) - I'm overriding translateSourcepaths in build.gradle with the source roots of each of the projects this project depends on.

Anyway, to automate the sourcepaths I did:

j2objcConfig {

    // Calculate source paths from project dependencies.
    translateFlags = "--build-closure"
    def sourcePaths = []
    project.configurations.compile.allDependencies.each { dep ->
          if (dep instanceof ProjectDependency) {
            def pj = ((ProjectDependency)dep).getDependencyProject()
            sourcePaths += pj.sourceSets.main.java.srcDirs
          }
        }
    translateSourcepaths = sourcePaths.join(':')

    // Further settings are listed in the "J2objcPluginExtension" class below
}

This seems to work (i.e. all tests pass) including with inner classes.

confile commented 9 years ago

Does it work for you with Dagger2 also?

advayDev1 commented 9 years ago

I'm not using Dagger2 on my current project, so I'm not sure. What I'm doing should work for the original issue as reported by @PaNaVTEC, which is a multi-module Java project - as that is the same case I have.

confile commented 9 years ago

You should create a pull request if you have improved something. If your where able to compile inner classes that is great.

advayDev1 commented 9 years ago

Sure, pull #22 - note it doesn't do anything with inner classes specially; just the original issue with java project dependencies.

confile commented 9 years ago

@advayDev1 I tested your code snippet and it did not work for inner types. Here is what I did:

    translateFlags = "--no-package-directories -use-arc --build-closure"
    def sourcePaths = []
    project.configurations.compile.allDependencies.each { dep ->
          if (dep instanceof ProjectDependency) {
            def pj = ((ProjectDependency)dep).getDependencyProject()
            sourcePaths += pj.sourceSets.main.java.srcDirs
          }
        }
    translateSourcepaths = sourcePaths.join(':')

And here is the only class in my project:

public class SomeClassX {

    private class MyPrivateClass {
        String test;
    }

    public interface MyInterface {
        void go();
    }
}

I get the following warnings while translating the Java source:

warning: could not find source path for com.example.SomeClassX.MyPrivateClass
warning: could not find source path for com.example.SomeClassX.MyInterface
brunobowden commented 9 years ago

Thanks for testing this. Please resolve it between the two of you and I'll then merge in the changes.

On Tue, Apr 7, 2015 at 11:18 AM Confile notifications@github.com wrote:

@advayDev1 https://github.com/advayDev1 I tested your code snippet and it did not work for inner types. Here is what I did:

translateFlags = "--no-package-directories -use-arc --build-closure"
def sourcePaths = []
project.configurations.compile.allDependencies.each { dep ->
      if (dep instanceof ProjectDependency) {
        def pj = ((ProjectDependency)dep).getDependencyProject()
        sourcePaths += pj.sourceSets.main.java.srcDirs
      }
    }
translateSourcepaths = sourcePaths.join(':')

And here is the only class in my project:

public class SomeClassX {

private class MyPrivateClass {
    String test;
}

public interface MyInterface {
    void go();
}

}

I get the following warnings while translating the Java source:

warning: could not find source path for com.example.SomeClassX.MyPrivateClass warning: could not find source path for com.example.SomeClassX.MyInterface

— Reply to this email directly or view it on GitHub https://github.com/brunobowden/j2objc-gradle/issues/12#issuecomment-90688027 .

advayDev1 commented 9 years ago

@brunobowden @confile, thanks.
I did the same setup as you, and I get no warnings:

:j2objcTranslate
Deleting j2objc build dir: /Users/USER/privateRepos/sandbox/test-j2objc-gradle1/build/j2objc
translating /Users/USER/privateRepos/sandbox/test-j2objc-gradle1/src/main/java/SomeClassX.java
Translated 1 file: 0 errors, 0 warnings
Translated 0 methods as functions

@confile, can you export a full public repo that reproduces your issue? Maybe something is different between the other files in our setup. And which version of j2objc binaries are you using?

More detail from my own testing: I also created a full class that uses an inner class, and also made a unit-test for that class using the inner class, and the ObjC translated unit-test for that class and its test translated, builds, and passes, vis:

:j2objcTranslate
Deleting j2objc build dir: /Users/USER/privateRepos/sandbox/test-j2objc-gradle1/build/j2objc
translating /Users/USER/privateRepos/sandbox/test-j2objc-gradle1/src/main/java/ClassWithInner.java
translating /Users/USER/privateRepos/sandbox/test-j2objc-gradle1/src/main/java/SomeClassX.java
translating /Users/USER/privateRepos/sandbox/test-j2objc-gradle1/src/test/java/ClassWithInnerTest.java
Translated 3 files: 0 errors, 0 warnings
Translated 0 methods as functions
:j2objcCompile
Compiling test binary: /user/USER/privateRepos/sandbox/test-j2objc-gradle1/build/j2objc/testrunner
:j2objcTest
Testing with: /Users/USER/privateRepos/sandbox/test-j2objc-gradle1/build/j2objc/testrunner
JUnit version 4.10
.
Time: 0

OK (1 test)

:j2objcCopy
Deleting destDir to fill with generated objc files... /Users/USER/privateRepos/sandbox/test-j2objc-gradle1/objc/j2objc-gen

BUILD SUCCESSFUL
/**
 *
 */
public class ClassWithInner {

    public InnerInterface makeInnerInstance() {
        return new InnerInterface() {
            @Override
            public int doIt() {
                return 42;
            }
        };
    }

    public static interface InnerInterface {
        public int doIt();
    }
}
import junit.framework.Assert;
import junit.framework.TestCase;

/**
 *
 */
public class ClassWithInnerTest extends TestCase {

    public void testDoIt() throws Exception {
        ClassWithInner.InnerInterface interf =
                new ClassWithInner().makeInnerInstance();
        Assert.assertEquals(42, interf.doIt());
    }
}
confile commented 9 years ago

@advayDev1 You should only include source jar automatically to the source path.

advayDev1 commented 9 years ago

@confile sorry I don't understand what you mean. If you still have a failing test case can you provide a precise repro in terms of a gist or repo?

On Tue, Apr 7, 2015, 11:06 PM Confile notifications@github.com wrote:

@advayDev1 https://github.com/advayDev1 You should only include source jar automatically to the source path.

— Reply to this email directly or view it on GitHub https://github.com/brunobowden/j2objc-gradle/issues/12#issuecomment-90815456 .

confile commented 9 years ago

@advayDev1 What I mean is the following. With:

def sourcePaths = []
    project.configurations.compile.allDependencies.each { dep ->
          if (dep instanceof ProjectDependency) {
            def pj = ((ProjectDependency)dep).getDependencyProject()
            sourcePaths += pj.sourceSets.main.java.srcDirs
          }
        }
    translateSourcepaths = sourcePaths.join(':')

you include all dependencies, i.e., jar from the project dependencies block to your project. Right? If so it should only be the source jars.

advayDev1 commented 9 years ago

No my understanding is that is not the case. ProjectDependency exists only when one java source project depends on another, no jars are involved. see gradle.org docs for the Dependency super interface, which includes all other kinds of dependencies like jars; that is why I check instanceof. My own project has both jars and project sources and this works fine for me.

Also @confile, do you still have a failing test case? If so I'd love to see it and try to fix it or otherwise let @brunobowden go ahead with the merge.

On Tue, Apr 7, 2015, 11:13 PM Confile notifications@github.com wrote:

@advayDev1 https://github.com/advayDev1 What I mean is the following. With:

def sourcePaths = [] project.configurations.compile.allDependencies.each { dep -> if (dep instanceof ProjectDependency) { def pj = ((ProjectDependency)dep).getDependencyProject() sourcePaths += pj.sourceSets.main.java.srcDirs } } translateSourcepaths = sourcePaths.join(':')

you include all dependencies, i.e., jar from the project dependencies block to your project. Right? If so it should only be the source jars.

— Reply to this email directly or view it on GitHub https://github.com/brunobowden/j2objc-gradle/issues/12#issuecomment-90817637 .

confile commented 9 years ago

@advayDev1 I do not understand why you override the `translateSourcepaths. I need to do something like the following:

translateSourcepaths "${projectDir}/libSrc/javax.inject-1-sources.jar:${projectDir}/libSrc/dagger-2.0-SNAPSHOT-sources.jar"

which is impossible if you do the override.

confile commented 9 years ago

@brunobowden until this is not clear it should not be merged.

advayDev1 commented 9 years ago

Please check out the actual pull #22 , I am not overriding that variable. That was just the snippet I used when figuring this out.

On Wed, Apr 8, 2015, 3:43 AM Confile notifications@github.com wrote:

@brunobowden https://github.com/brunobowden until this is not clear it should not be merged.

— Reply to this email directly or view it on GitHub https://github.com/brunobowden/j2objc-gradle/issues/12#issuecomment-90876877 .

confile commented 9 years ago

@advayDev1 Okay looks good to me.

@brunobowden You can merge the pull request.

brunobowden commented 9 years ago

Thanks to both of you. Now merged.

On Wed, Apr 8, 2015 at 3:53 AM Confile notifications@github.com wrote:

@advayDev1 https://github.com/advayDev1 Okay looks good to me.

@brunobowden https://github.com/brunobowden You can merge the pull request.

— Reply to this email directly or view it on GitHub https://github.com/brunobowden/j2objc-gradle/issues/12#issuecomment-90879323 .

confile commented 9 years ago

@brunobowden This issue is fixed now right?