New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option to manually add an import #512

Closed
vovcacik opened this Issue Oct 21, 2016 · 18 comments

Comments

10 participants
@vovcacik

vovcacik commented Oct 21, 2016

Hi,
I am aware that JavaPoet is automatically managing imports, but I would appreciate possibility to manually add non-static import.

The need occurs when I copy method implementation from an existing class to a class I build with JavaPoet. I don't really know what the method implementation looks like, nor I care. But the implementation may be depending on an import statement, which JavaPoet is not and can't be aware of.

Note that parsing method implementation is heroic task, which I want to avoid.
Thanks

poor man's workaround

This one is for field initializers, but same applies to code in methods.

initializerString = initializerString.replaceAll("HashSet", "java.util.HashSet"); // etc.
@theangrydev

This comment has been minimized.

theangrydev commented Nov 3, 2016

+1

@xiaolongWangDev

This comment has been minimized.

xiaolongWangDev commented Nov 22, 2016

++

@MingweiSamuel

This comment has been minimized.

MingweiSamuel commented Jan 9, 2017

+1. I need to import a class for a varargs argument and there is no way to do it without getting hacky. This would make it a lot easier.

edit: I redact my +1

@JakeWharton

This comment has been minimized.

Collaborator

JakeWharton commented Jan 9, 2017

@MingweiSamuel

This comment has been minimized.

MingweiSamuel commented Jan 10, 2017

Basically something along the lines of

obj.call(someVar, 1234, "asdf", new Param("width", width), new Param("height", height), new Param("api_key", apiKey));

The first few args where some dynamic things and the last ones were varargs of some foreign type of varying length. I ended up just making a utility function elsewhere static Param[] makeParams(Object... paired) { ... } which paired up the arguments, and then used a stringbuilder to generate the makeParams call.

@JakeWharton

This comment has been minimized.

Collaborator

JakeWharton commented Jan 10, 2017

You can use a CodeBlock which will correctly import types.

@vovcacik

This comment has been minimized.

vovcacik commented Jan 18, 2017

Just to comment on the short Samuel's and Jake's discussion above, I could not use CodeBlock as it won't detect types in unparsed Java code.

@clun

This comment has been minimized.

clun commented Feb 21, 2017

+1, it works with CodeBlock

//[...]
ParameterizedTypeName typeArrayList = ParameterizedTypeName.get(ArrayList.class, String.class);
mybuilder.initializer(CodeBlock.builder().addStatement("new $T()", typeArrayList).build());
@bjakke

This comment has been minimized.

bjakke commented Feb 22, 2017

+1, would offer more options to use javapoet.

Possible use case: Adding custom "unknown" code to generated classes.
If javapoet is used as part of an utility that generates code e.g. for a domain specific case, like xjc generates .java from an xml schema, users of that utility might want to add custom implementations/code to the generated classes.

Lets say there is one method implementation that should be added to the generated java file and that method is specific to that file, i.e. it cannot be inherited from a common super class. In addition the generated file is extended by another generated file that should inherit this method implementation, which rules out extending the generated class manually.

I would assume the source of this method code would come in 2 parts: the code and imports, as most likely it would be written as a separate class. The method body can be added as raw via CodeBlock.add for each line, however the imports cannot be added.

@JakeWharton

This comment has been minimized.

Collaborator

JakeWharton commented Feb 22, 2017

@theangrydev

This comment has been minimized.

theangrydev commented Feb 22, 2017

I think you're missing the point a bit, there is a cross section of the javapoet user base that would find this feature useful. It doesn't matter what the idealistic use cases are, some users will never know about nor find out about the "correct" way to implement what they are trying to achieve. Adding this feature will make javapoet more valuable to those people and will not hurt people that are using javapoet in other supported ways. Just my 2 cents...

@JakeWharton

This comment has been minimized.

Collaborator

JakeWharton commented Feb 22, 2017

Sorry but that doesn't come close to convincing me of its utility in the library. Every provided use case thus far is better served by something else or doesn't actually play well with the existing behavior such that it will actively cause problems. We're not going to add a feature because users think they want it when it actually undermines the value the library aims to provide.

@theangrydev

This comment has been minimized.

theangrydev commented Feb 22, 2017

Your choice, just trying to help give you some perspective. If you have strong opinions on how you want the library to evolve then that's fine; your user base will naturally end up being people who are solving the kinds of problems you have envisaged. If you want a wider user base then at some point there have to be compromises on what is "right" vs what people want or "think they want" as you put it, to allow people to solve problems you did not envisage. But if that is not one of your goals for the project then that is fair enough.

@swankjesse

This comment has been minimized.

Member

swankjesse commented Feb 22, 2017

If you really want this, you can do it yourself in a few lines of code:

  public String injectImports(JavaFile javaFile, List<String> imports) {
    String rawSource = javaFile.toString();

    List<String> result = new ArrayList<>();
    for (String s : rawSource.split("\n", -1)) {
      result.add(s);
      if (s.startsWith("package ")) {
        result.add("");
        for (String i : imports) {
          result.add("import " + i + ";");
        }
      }
    }
    return String.join("\n", result);
  }

I don’t want to add this to JavaPoet because I don’t want to give our users the impression that this will work reliably. To work reliably we’d need to parse source code, and that’s a lot of work.

I’d rather offer a complete solution to a smaller userbase, than offer an incomplete solution to a larger userbase. That way users can be confident that if JavaPoet offers a feature it’ll probably work well.

@swankjesse swankjesse closed this Feb 22, 2017

@JakeWharton

This comment has been minimized.

Collaborator

JakeWharton commented Sep 7, 2017

@andromedcodes

This comment has been minimized.

andromedcodes commented Sep 20, 2018

This feature would not help your issue. To add an import you need the package name and the class name which means you could call ClassName.get(packageName, className) and emit the reference normally.

On Thu, Sep 7, 2017 at 7:12 AM Thomas Bigger ***@***.***> wrote: +1 for the feature My use case is that I'm generating an entity pojo class into another project (not in the current java poet project) then creating an interface directly after which has a super-interface with a generic type of this entity. The import cannot be resolved because it resides in another project. At the moment I'm stuck using ClassName.bestGuess(entityName) then letting the IDE resolve the import within the other project which is not optimal. — You are receiving this because you commented. Reply to this email directly, view it on GitHub <#512 (comment)>, or mute the thread https://github.com/notifications/unsubscribe-auth/AAEEEXi_lJPW2mu4PQtud7F_gJUJiXe9ks5sf8-FgaJpZM4KdA-i .

@JakeWharton what if you will need to reference a class out of your scope? exp the annotation processor is being implemented inside a java library and sometimes you need to use a Type from android SDK, how would you reference ColorDrawable.class for example?

@kenzierocks

This comment has been minimized.

Contributor

kenzierocks commented Sep 20, 2018

You get a TypeName for it like so: ClassName.get("android.graphics.drawable", "ColorDrawable")

Then you can use that wherever $T is accepted, and it will import it for you. If you want to explicitly reference the Class for it, you can do $T.class and pass the ClassName.

@andromedcodes

This comment has been minimized.

andromedcodes commented Sep 20, 2018

You get a TypeName for it like so: ClassName.get("android.graphics.drawable", "ColorDrawable")

Then you can use that wherever $T is accepted, and it will import it for you. If you want to explicitly reference the Class for it, you can do $T.class and pass the ClassName.

Thanks alot!!! that's exactly what i needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment