Creating default implementation using unmanaged classes

Continuing the discussion from New model confusion:

Creating default implementations

This is relatively easy to get working

@Managed
interface MyComponent extends ComponentSpec {
}

class Rules extends RuleSource {
  @ComponentType
 void register( TypeBuilder<MyComponent> builder ) {}
}

But if one needs something more complex and try doing


interface MyComponent extends ComponentSpec {
}
class DefaultMyCompoent implements MyComponent { ... }

class Rules extends RuleSource {
  @ComponentType
  void register( TypeBuilder<MyComponent>builder ) {
    build.defaultImplementation(DefaultMyComponent)
  }
}

and it wil fail with No factory registered to create an instance of implementation classDefaultMyComponent’.

I’ve looked through a number of examples in the Gradle code base that does that, my I cannot find the way it registers the factory.

I think the annotation should be @ComponentType, not @ComponentSpec. At least that works for me. Although my default implementation also extends BaseComponentSpec.

Indeed, that was late-night typing. I’ve edited the post to correct it.

Using BaseComponentSpec removes the error, but that it not quite correct for my implementation.

The documentation states that Components extend the ComponentSpec base interface. I did not actually wanted to use baseComponentSpec as that implements SourceComponentSpec (i.e. has a getSources which returns a LanguageSourceSet ) which I don’t need.

Could it be that a plain extension of ComponentSpec (as opposed to one of the more specific interfaces) is not a common use case outside examples and thus is either incorrectly documented, or broken?

In this case, what does your component represent? Does it even make sense not to use the source/binary interfaces?

There are two parts to this:

One is more experimentation. Finding gaps in the dcumentation and seeing what can be done at various levels is part of this. This is importsnt from a view of writing more recipes for specific use cases. In this case I can expect many failures ang going down routes which will turn out not be feasible.

The seocnd is more practical. I am looking at the GNU Make plugin as an example. The existing plugin as makeInputs and makeOutputs as a way to specify input and output files in order for Gradle to perform up to date checks, It requires a person to know what the Makefile will produce and list them in the buildscript.

What I am trying is to build a model DSL that will not only allow a script author to specify the outputs, but also state what kind of artifact it is. For instance if the Makefile produces a shared library, then it would be nice for a native compoenents just to reference that library like it would for any other Gradle-built or prebuilt library. IN some or other way this will eventually require getBinaries to work.

THe part I am looking at curretnly is the inputs. A SourceComponentSpec uses LanguageSourceSet which is modelled towards a set of well-known group of source files i.e. *.java or *.cpp. With a Make project it is just an arbitrary set of files in a folder usually. I am not sure whether that is well modelled with a LanguageSourceSet, this the experimentation to see if there is an alternative way of implementing it.

The current experiment, and you mentioning BaseComponentSpec has lead me there, is to extend the internal DefaultComponentSpec (from which BaseComponentSpec derives anyway) and see how that works. I am not really concerned that DefaultComponentSoec is internal at this point, for if the experiement works, there might be a valid case for having such a class in the API.

I’ve ignored Language in LanguageSourceSet when I needed to use one. I suppose you might say that my plugin is similar to the GnuMake one you mention, in that it wraps Unreal Engine 4’s UnrealBuildTool and the myriad of small scripts and steps one needs to use with it. I use an EditorSourceSet which just takes a list of every single file that could affect the build; source, configs, data, etc., and I then let the actual UE4 build tool sort out if anything needs to be done or not. Thus I can speed up no-op builds using gradle’s logic, and actual builds are so slow anyway, that it doesn’t matter the dependencies need to be checked twice.

I suppose this is somewhat abusing the original intent of the tool, so I don’t actually feel too bad about using LanguageSourceSet in this case, but of course something less specific would be nice.

1 Like