[ANN] Rearranger plugin - new version 0.9 released

The plugin rearranges class and class member declarations according to a user-specified order.

New in version 0.9:
- Comments may be inserted conditionally based on whether items matched any or all of the preceding and/or subsequent rules.

A comment may be emitted:

For example, if your Class Member Order is defined as follows:


then the "PRIVATE FIELDS" comments will only appear if one or more private fields were found; likewise, the "STATIC FIELDS" comments will only appear if one or more static fields were found. The "FIELDS BEGIN/END HERE" comments will only appear if at least one private or static field was found. In the case where there were private fields but no static fields, output might be:


Version 0.9 also fixes deletion of comments inserted by a previous run of the Rearranger when those comments were adjacent.

The plugin is available via Plugin Manager or at http://www.intellij.org/twiki/bin/view/Main/RearrangerPlugin.

-Dave

20 comments

very nice. One minor niggle. My first comment rule that is matched on my file is for private fields. Repeated uses of Rearranger results in it appearing multiple times. This doesn't happen with any of the other comments. I can't find any other difference between this comment and the others though.

Thanks for the tool.

0

Joe,

could you send me an example of your comment problem? There's something funny about the placement of the comment (from Psi's point of view, not yours. :) I think I need from the beginning of class up to and including your private fields. I'd like to see it in the state where an extra comment has been inserted.

Also would be great if you could send me the ]]> XML element from the idea/config/options/other.xml file so I can see your configuration. It should be at the end of the file or close to it.

-Dave

0

no problem... heres the class, though blank lines are lost. Another problem seems to be that if I make changes to the Rearranger file I get duplicate comments if I rerun rearranger.


0) { putLock.notifyAll(); } } } public Object take() { Object obj = takeNext(); if (obj != null) { return obj; } else { synchronized (putLock) { waitCount++; while (true) { obj = takeNext(); if (obj != null) { waitCount--; return obj; } try { putLock.wait(); } catch (InterruptedException e) { logCat.error("Blocking Queue threw interrupt", e); return null; } } } } } //********************************* PACKAGE/PROTECTED METHODS ******************************** protected Object takeNext() { synchronized (takeLock) { return super.takeNext(); } } } ]]>

and here's the relevant configuration info...

]]>

0

Thanks for the plugin. Any chance you could put in support to specify
where initializer blocks go? (Or maybe its already there and I can't
see it)

Cheers,
N.

0

I think it will do that for you if you select "static initializer" on the Class Member Order...Method dialog. Checkbox is about halfway down.

I'll pass along a warning about moving static fields and static initializers; their order in the class file defines the order in which they'll be initialized. If they depend on values of other static fields, their initial values could be different by changing the order.

Let me know if that works for you,
-Dave

0

dur.. theres me with the field radio button selected! Should that not
just read "initializer" as it appears to work for instance initializers too?

N.

Dave Kriewall wrote:

I think it will do that for you if you select "static initializer" on the Class Member Order...Method dialog. Checkbox is about halfway down.

I'll pass along a warning about moving static fields and static initializers; their order in the class file defines the order in which they'll be initialized. If they depend on values of other static fields, their initial values could be different by changing the order.

Let me know if that works for you,
-Dave


0

Hi Nathan,

Glad you found it. It's sure buried in a sea of checkboxes. (But not Czech boxes.)

Should that not just read "initializer" as it appears to work for instance initializers too?


Hmm, I think it only applies to static initializers. Isn't an instance initializer just another name for a constructor? Constructors are treated as plain old methods by Psi, whereas the static initializer has its own Psi entry. Perhaps your settings happen to move constructors next to the static initializer? If I'm wrong, send me a snippet of code.

-Dave

0

Hi Joe,

I'm working on your submitted code, but wanted to comment on what you wrote:

Another problem seems to be that if I make changes to the Rearranger file I get duplicate comments if I rerun rearranger.


When you say "make changes to the Rearranger file" do you mean change the plugin's configuration?

I am guessing that what you are seeing is something like this:



I don't know of any way to avoid this. I search the java file for any comment matching the current set of configured comments. If you change the set, I won't find old comments no longer in the set.

I suppose I could add the ability to specify a global "comment pattern." I would enforce that all currently configured comments match this pattern (or at least warn that the pattern doesn't match all configured comments). Then at the next rearrangement, the plugin would delete all comments in the file that match this pattern. As long as your pattern didn't change but was unique enough to prevent a false positive (we don't want to throw away real comments!), this would solve your problem.

So maybe your pattern would be

meaning //, at least 25 asterisks, anything with spaces, capital letters, or slash, and another 25 or more asterisks.

Is it worth it, IYO?

-Dave

0

actually, what I was referring to was me changing one comment, but rearrangement then adding an extra line to all my comment lines, even the ones that didn't change. Although your solution is an elegant one!

0

Ha! Your bug (many comments are duplicated) masked the problem. Once I fix it, you'll find that the plugin only "duplicates" comments that you reconfigure.

I'll ponder the "comment pattern" feature. It belongs on a general config panel, which I haven't needed yet.

I'm close to a fix for your bug. Hope to have it up tonight.
-Dave

0

No, instance initializers aren't constructors, they are just like static
initializers but without the 'static' keyword i.e.:

{
// do some instance based initialization.
}

vs.

static {
// do some class based initialization
}

Your plugin definitely moves both instance and static initializers when
the "static initializer" term is used, and it does distinguish between
the two if the static checkbox is checked, so the text should just be
'initializers'; if you check "not static" then you get "non-static
static initializers"!

N.

Dave Kriewall wrote:

Hmm, I think it only applies to static initializers. Isn't an instance initializer just another name for a constructor? Constructors are treated as plain old methods by Psi, whereas the static initializer has its own Psi entry. Perhaps your settings happen to move constructors next to the static initializer? If I'm wrong, send me a snippet of code.

-Dave


0

No, instance initializers aren't constructors, they are just like static
initializers but without the 'static' keyword i.e.:

{
// do some instance based initialization.
}


Interesting. Never heard about it.

Tom

0

Yes... they are incredibly useful once you know they are there. How
many times have you wrestled with deciding the correct chaining of
overloaded constructors so that you didn't have to duplicate your
initialization code. Now the pain can go! Basically pretty well
everything that does not rely on specific c'tor params can and should go
in there, and you end up with an incredibly elegant result.

Gives me warm fuzzies just thinking about it! Hmmm, now to actually
get a life ;)

N.

Thomas Singer wrote:

>> No, instance initializers aren't constructors, they are just like
>> static initializers but without the 'static' keyword i.e.:
>>
>> {
>> // do some instance based initialization.
>> }


Interesting. Never heard about it.

Tom


0

IMO they're quite bad and should generally be avoided. They can lead to some
very obscure bugs. For instance you might think that the following would
print out the number 10, but actually it won't compile:

class A {
{
val = 10;
System.out.println(val);
}
private int val;
}

You can assign a value to the 'val' member before it is declared, but you
can't read a value from it.

I think it's much better to just have an init() method which is called from
each constructor that to try and use an instance initialiser.

Another point is that instance initialisers don't show up in IDEAs structure
view. Actually, I just checked and the same is true for static initialisers.
I'm off to file a bug report...

Vil.

Nathan Brown wrote:

Yes... they are incredibly useful once you know they are there. How
many times have you wrestled with deciding the correct chaining of
overloaded constructors so that you didn't have to duplicate your
initialization code. Now the pain can go! Basically pretty well
everything that does not rely on specific c'tor params can and should go
in there, and you end up with an incredibly elegant result.

Gives me warm fuzzies just thinking about it! Hmmm, now to actually
get a life ;)

N.

--
Vilya Harvey
vilya.harvey@digitalsteps.com / digital steps /
(W) +44 (0)1483 469 480
(M) +44 (0)7816 678 457 http://www.digitalsteps.com/

0

This class :

public class InitializerTest
{
private int _foo;

{
_foo = 3;
System.out.println("InitializerTest.'instance initializer' : _foo =
" + _foo);
}

public InitializerTest()
{
}

public static void main(String[] args)
{
new InitializerTest();
}
}

compiles and produces this output:
InitializerTest.'instance initializer' : _foo = 3

So it seems to work?

N.

Vilya Harvey wrote:

IMO they're quite bad and should generally be avoided. They can lead to
some very obscure bugs. For instance you might think that the following
would print out the number 10, but actually it won't compile:

class A {
{
val = 10;
System.out.println(val);
}
private int val;
}

You can assign a value to the 'val' member before it is declared, but
you can't read a value from it.

I think it's much better to just have an init() method which is called
from each constructor that to try and use an instance initialiser.

Another point is that instance initialisers don't show up in IDEAs
structure view. Actually, I just checked and the same is true for static
initialisers. I'm off to file a bug report...

Vil.

Nathan Brown wrote:

>> Yes... they are incredibly useful once you know they are there. How
>> many times have you wrestled with deciding the correct chaining of
>> overloaded constructors so that you didn't have to duplicate your
>> initialization code. Now the pain can go! Basically pretty well
>> everything that does not rely on specific c'tor params can and should
>> go in there, and you end up with an incredibly elegant result.
>>
>> Gives me warm fuzzies just thinking about it! Hmmm, now to actually
>> get a life ;)
>>
>> N.

0

Ah sorry I missed the position of the variable declaration... :)

This is why all my initializer blocks go after my var declarations -
hence what I wanted to do with the rearranger in the first place!

N.

Nathan Brown wrote:

This class :

public class InitializerTest
{
private int _foo;

{
_foo = 3;
System.out.println("InitializerTest.'instance initializer' : _foo =
" + _foo);
}

public InitializerTest()
{
}

public static void main(String[] args)
{
new InitializerTest();
}
}

compiles and produces this output:
InitializerTest.'instance initializer' : _foo = 3

So it seems to work?

N.

Vilya Harvey wrote:

>> IMO they're quite bad and should generally be avoided. They can lead
>> to some very obscure bugs. For instance you might think that the
>> following would print out the number 10, but actually it won't compile:
>>
>> class A {
>> {
>> val = 10;
>> System.out.println(val);
>> }
>> private int val;
>> }
>>
>> You can assign a value to the 'val' member before it is declared, but
>> you can't read a value from it.
>>
>> I think it's much better to just have an init() method which is called
>> from each constructor that to try and use an instance initialiser.
>>
>> Another point is that instance initialisers don't show up in IDEAs
>> structure view. Actually, I just checked and the same is true for
>> static initialisers. I'm off to file a bug report...
>>
>> Vil.
>>
>> Nathan Brown wrote:
>>
>>> Yes... they are incredibly useful once you know they are there. How
>>> many times have you wrestled with deciding the correct chaining of
>>> overloaded constructors so that you didn't have to duplicate your
>>> initialization code. Now the pain can go! Basically pretty well
>>> everything that does not rely on specific c'tor params can and should
>>> go in there, and you end up with an incredibly elegant result.
>>>
>>> Gives me warm fuzzies just thinking about it! Hmmm, now to actually
>>> get a life ;)
>>>
>>> N.



0

OK so the plot thickens. Running this class:

public class InitializerTest
{
{
_foo = 3;
System.out.println("InitializerTest.'instance initializer' :
getFoo() = " + getFoo());
}

private int _foo;

public InitializerTest()
{
}

public static void main(String[] args)
{
new InitializerTest();
}

public int getFoo()
{
return _foo;
}
}

gives this output:
InitializerTest.'instance initializer' : getFoo() = 3

So it looks like you can access the properly initialized value of the
variable via an accessor method irrespective of where the variable is
declared. Coupled with the fact that the compiler stops you accessing
the variable directly early, I don't see how they can be classed as a
"bad thing" or could cause bugs. In fact, I would say it is more likely
a bug to creep in via a missing init() call if you were using init()'s.

Please let me know if I'm missing anything here?

N.

0

That's actually a perfect example of the sort of obscure behaviour I was
talking about & why I think they should be avoided. That kind of
inconsistency is dangerous IMO. I'm not saying that they can't be used
correctly, just that for me they fall on the wrong side of the usefulness
vs. potential pitfall line.

Vil.

Nathan Brown wrote:

OK so the plot thickens.

]]>

--
Vilya Harvey
vilya.harvey@digitalsteps.com / digital steps /
(W) +44 (0)1483 469 480
(M) +44 (0)7816 678 457 http://www.digitalsteps.com/

0

Nathan,

I was oblivious to the existence of non-static initializers, but you're right, it should be renamed to just initializers. I have run into the exact problem you described with overloaded constructors. This sounds cool. Of course, I won't use them in such a way that Vil would not approve! :-D (So maybe I won't use them..)

(I wonder if the new Java Memory Model group has wrestled with them. Constructors that provide field references to code outside the constructor seem to give them fits, especially if the field is final. Your println() is a good example.)

Thanks for doing the testing to see if the 'is static' criterion would distinguish static from non-static initializers.

-Dave

0

P.S. A minor side effect of renaming the 'static initializer' to 'initializer' is that the setting will be lost. You'll have to reconfigure those items, sorry.

-D

0

Please sign in to leave a comment.