108

I'm working now together with others in a grails project. I have to write some Java-classes. But I need access to an searchable object created with groovy. It seems, that this object has to be placed in the default-package.

My question is: Is there a way to access this object in the default-package from a Java-class in a named package?

Viorel Florian
  • 594
  • 9
  • 29
Mnementh
  • 50,487
  • 48
  • 148
  • 202

5 Answers5

135

You can’t use classes in the default package from a named package.
(Technically you can, as shown in Sharique Abdullah's answer through reflection API, but classes from the unnamed namespace are not in scope in an import declaration)

Prior to J2SE 1.4 you could import classes from the default package using a syntax like this:

import Unfinished;

That's no longer allowed. So to access a default package class from within a packaged class requires moving the default package class into a package of its own.

If you have access to the source generated by groovy, some post-processing is needed to move the file into a dedicated package and add this "package" directive at its beginning.


Update 2014: bug 6975015, for JDK7 and JDK8, describe an even stricter prohibition against import from unnamed package.

The TypeName must be the canonical name of a class type, interface type, enum type, or annotation type.
The type must be either a member of a named package, or a member of a type whose outermost lexically enclosing type is a member of a named package, or a compile-time error occurs.


Andreas points out in the comments:

"why is [the default package] there in the first place? design error?"

No, it's deliberate.
JLS 7.4.2. Unnamed Packages says: "Unnamed packages are provided by the Java SE platform principally for convenience when developing small or temporary applications or when just beginning development".

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 7
    As I've explained to other people before, the default package is a second-class citizen in the Java world. Just Don't Do That. :-) – C. K. Young Nov 12 '08 at 12:58
  • 1
    Seems I have to learn Groovy (on a very time-constrained project) or code in the default-package. :-( – Mnementh Nov 12 '08 at 13:02
  • 11
    @ChrisJester-Young if so why is it there in the first place? design error? – Pacerier Oct 18 '11 at 12:32
  • Why it was deprecated? – Suzan Cioc Jan 18 '14 at 14:09
  • @SuzanCioc do you mean: "why after J2SE1.4, can you no longer access the default package?" – VonC Jan 18 '14 at 14:33
  • @VonC yes this is what I mean – Suzan Cioc Jan 18 '14 at 14:40
  • @SuzanCioc Because classes from the unnamed namespace are not in scope in an import declaration: the risk of *naming collision* was simply too important in that unnamed namespace. – VonC Jan 18 '14 at 14:42
  • @VonC what is the principal difference between "root" package and any other top-level packages, like `com` or `org`? May be let us prohibit to import them too? – Suzan Cioc Jan 18 '14 at 16:30
  • @SuzanCioc `com` or `org` are based on a naming *convention*, as opposed to the "`root`" package, which is part of the language specification. You have to trust conventions, but the language can evolve its specification. – VonC Jan 18 '14 at 16:34
  • I agree that both conventions ans specifications can evolve. So if we judge to evolve root package specification because of dangerous name clash, then we can evolve conventions on the same reason: NEVER put your class into one-level named package or you will be in danger! – Suzan Cioc Jan 18 '14 at 16:39
  • @SuzanCioc I agree. The difference, though, is that conventions evolve by their *users*, while specifications evolves by the language designers: two different communities, both in scale and in decision process. – VonC Jan 18 '14 at 16:41
  • Downvote because although I agree with the sentament, Sharique's answer is correct and this one is wrong. – Bill K Oct 16 '14 at 00:45
  • @BillK Good point. i have included a reference to Sharique's answer. I have also documented a recent (2014) evolution of JLS8 (Java Language Specification) reinforcing the fact a type *must* be a member of a type package. – VonC Oct 16 '14 at 05:49
  • Thanks, -1 removed... I wonder how the JLS change will affect Groovy scripts because they are generally in the default package (It wouldn't make much sense to have them anywhere else). I suppose groovy could assign a fake package automatically--that would be no more hacky than anything else in groovy :) – Bill K Oct 16 '14 at 17:24
  • @VonC, Aside from reflection, what about the new invocation mechanisms? – Pacerier Jul 29 '17 at 23:18
  • @VonC, Yep, I heard they gave dynamic coding a complete rehaul, making scripting languages like JS, Scala, and Kotlin First class. – Pacerier Aug 06 '17 at 21:58
  • 1
    @Pacerier "why is [the default package] there in the first place? design error?" No, it's deliberate. JLS [7.4.2. Unnamed Packages](https://docs.oracle.com/javase/specs/jls/se8/html/jls-7.html#jls-7.4.2) says: *"Unnamed packages are provided by the Java SE platform principally for **convenience** when developing **small or temporary applications** or when just **beginning development**"*. – Andreas Apr 28 '19 at 22:55
  • @Andreas Thank you for this feedback. I have included your comment in the answer for more visibility. – VonC Apr 29 '19 at 07:31
63

In fact, you can.

Using reflections API you can access any class so far. At least I was able to :)

Class fooClass = Class.forName("FooBar");
Method fooMethod = fooClass.getMethod("fooMethod", String.class);

String fooReturned = (String)fooMethod.invoke(fooClass.newInstance(), "I did it");
Holger
  • 285,553
  • 42
  • 434
  • 765
  • For Scala, the following code works: `val bar = "hi"; val fooClass = Class.forName("FooClass"); val fooMethod = fooClass.getMethod("foo", classOf[Array[String]]); val fooReturned = fooMethod.invoke(fooClass.newInstance(), Array(bar));` – Jus12 Aug 14 '12 at 08:58
  • 2
    Great answer, +1. Since the question was groovy, however, you can use duck typing (like Duct taping I guess)... `Class.forName("FooBar").newInstance().fooMethod("I did it")` – Bill K Oct 16 '14 at 00:47
  • 1
    Well, if I have two classes named FooBar from two differents jar files, which one will be called? – Davide Mar 15 '21 at 15:59
7

Use jarjar to repackage the jar file with the following rule:

rule * <target package name>.@1

All classes in the default package of the source jar file will move to the target package, thus are able to access.

Sean
  • 71
  • 1
  • 3
  • 4
    a demo of how to use jarjar would be great – BiGGZ Mar 02 '17 at 21:34
  • @BiGGZ: See the [README.md](https://github.com/shevek/jarjar/blob/master/README.md) file on the jarjar github repo to see how to use jarjar with ant, gradle or the command line. – lucidiot Oct 12 '17 at 09:14
3

You can use packages in the Groovy code, and things will work just fine.

It may mean a minor reorganization of code under grails-app and a little bit of a pain at first, but on a large grails project, it just make sense to organize things in packages. We use the Java standard package naming convention com.foo.<app>.<package>.

Having everything in the default package becomes a hindrance to integration, as you're finding.

Controllers seem to be the one Grails artifact (or artefact) that resists being put in a Java package. Probably I just haven't figured out the Convention for that yet. ;-)

Ken Gentle
  • 13,277
  • 2
  • 41
  • 49
1

just to complete the idea:

From inside default-package you can access objects resided in named packages.

Java bee
  • 2,522
  • 1
  • 12
  • 25