0

I'm modding Minecraft and I imported a mod jar as dependency. However, the compiler prompted error since the class from the dependency mod I invoked method of implemented interfaces from other mods.

In my code, I invoked a method of a class from the dependency jar. There are some simplified code that demonstrate what the code is like.

// From my mod
public class MachineIgniterListener {
    
    public void onPlayerInteract(PlayerInteractEvent event) {
        BaseMetaTileEntity tileEntity = getMachineInEventIfItIs(event);
        if (tileEntity == null) return;

        tileEntity.doEnergyExplosion(); 
    }

}

where BaseMetaTileEntity comes from the dependency mod, and it implements several interfaces from other mods

// From dependency mod
public class BaseMetaTileEntity extends CommonMetaTileEntity 
        implements IActionHost, IAlignmentProvider, IConstructableProvider... {

    public void doEnergyExplosion() {
        // do some explosion
    }
}

IActionHost, IAlignmentProvider, and other interfaces are from other mods which I haven't include in the classpath, resulting in the compiler complaining

        tileEntity.doEnergyExplosion();
                  ^
   class file for appeng.api.networking.security.IActionHost not found

I think, in terms of JVM bytecode, the code does not require knowing what interfaces the class implements to compile (which I might be wrong about it), so I'm expecting the code compiles without the depended jars added to the classpath. However, the compiler requires all the jars to be present. Since I'm coding in legacy versions of Minecraft, finding some mod that it requires can be very tidious.

I used Gradle to include the jar file in my project. Since I'm new to Gradle, I tried different kinds of dependency configurations, and none of them solved the problem.

dependencies {
    // compile files("dependency_mod.jar")
    // implementation files("dependency_mod.jar")
    // api files("dependency_mod.jar")
    // runtimeOnly files("dependency_mod.jar") I can't even refer to the classes with this one
    // Yes I tried lol

    compileOnly files("dependency_mod.jar")
}

I wonder if there are ways to make the code compile without adding all these jars to the dependencies. Am I doing wrong with the Gradle settings? Or there's no other ways around than adding the jars?

Also, if this is relevant, I'm using IntelliJ with Gradle 6.9.1, Java 8, and FalsePattern / ExampleMod1.7.10 modding toolchain template

See also: A question described that resulted in expected behavior - Java Compiler transistive type checking behaviour

  • You can't. That would violate the Java Language Specification. – user207421 Apr 27 '23 at 12:04
  • @user207421 The case in the 'see also' worked as expected, I wonder how that came to be... or if that was just an abstract showcase. – Ash Hagi Apr 27 '23 at 12:13
  • 1
    That is a different type structure. In the example in that question, the dependency is in the implementation code and doesn't affect the type signature. In your example the dependency affects the type signature. – Stephen C Apr 27 '23 at 12:55
  • 1
    The case in the linked question is “working as expected” except for the crucial part of your question. Look at the end of the question where it asked “*Also, what happened if use a function in class A using object of B which is in Class C but not overridden in class B*”. You just found out what happens, in fact, you found out that any invocation of a method in B will require the supertypes. But if you don’t need any method from the interfaces, you may add a jar containing empty dummy versions of the interfaces… – Holger Apr 28 '23 at 07:47
  • @Holger So, I wonder if calling the constructor of class B from class A is different from calling a method of class B from class A? – Ash Hagi Apr 29 '23 at 06:30
  • 1
    It could be, as constructors are not inherited. However, it’s all just compiler implementation dependent. The standard does not mandate a particular behavior. – Holger Apr 29 '23 at 15:38

1 Answers1

1

I wonder if there are ways to make the code compile without adding all these jars to the dependencies.

Short answer: Probably not, you have to add all the dependencies.

In your Gradle file you define the libs that your mod uses in order to compile your app. What Gradle will do then is to connect all of those classes together and build your classpath. Gradle is able to find (and download) all the missing dependencies from repositories, such as maven's. The packages there can declare other dependencies themselves and so on.

What Gradle (and the build tools general) is good for is to traverse those complicated dependency trees and fetch the jars that each projects needs/declares.

In your dependencies though you defined a local jar dependency. That means that you are saying to Gradle:

  • Don't look at a remote repository to get the jar, but I have it ready for you in a local directory

But your local directory is not a repository and it doesn't tell to Gradle which other jars it needs and where to go from there.

Now it depends on the jar that you downloaded if your project will compile. If the jar doesn't contain its dependencies, then you have to find those additional jars yourself, download them and add them to Gradle manually so it will connect the dots and build the classpath.

But check if there's a possibility that there's a dependency_mod.jar out there that contains all of its dependencies in the jar itself - that's generally called a fat or uber jar

Skod
  • 435
  • 6
  • 16
  • Thanks for the quick answer! However, the other mods are soft dependencies, and also, the question in the 'see also' resulted in the behavior I wanted using Gradle. I wonder if my build tools can behave like that. – Ash Hagi Apr 27 '23 at 12:09
  • Cool, do you mind sharing your answer and what gradle task you used to get the error? – Skod Apr 27 '23 at 12:17