20

I see about decorator example in Python:

def makebold(fn):
    def wrapped():
        return "<b>" + fn() + "</b>"
    return wrapped

def makeitalic(fn):
    def wrapped():
        return "<i>" + fn() + "</i>"
    return wrapped

@makebold
@makeitalic
def hello():
    return "hello world"

print hello() ## returns <b><i>hello world</i></b>

And got some curious how it can be implement in Java, so I search and got some example using Decorator Design Pattern.

public class Main {

    public static void main(String[] args) {
        Wrapper word = new BoldWrapper(new ItalicWrapper());
        // display <b><i>hello world</i></b>
        System.out.println(word.make("Hello World"));
    }
}

public interface Wrapper {

    public String make(String str);

}

public class BoldWrapper implements Wrapper {

    private Wrapper wrapper;

    public BoldWrapper() {

    }

    public BoldWrapper(Wrapper wrapper) {
        this.wrapper = wrapper;
    }

    @Override
    public String make(String str) {
        if(wrapper != null) {
            str = wrapper.make(str);
        }

        return "<b>" + str + "</b>";
    }

}

public class ItalicWrapper implements Wrapper {

    private Wrapper wrapper;

    public ItalicWrapper() {

    }

    public ItalicWrapper(Wrapper wrapper) {
        this.wrapper = wrapper;
    }

    @Override
    public String make(String str) {
        if(wrapper != null) {
            str = wrapper.make(str);
        }

        return "<i>" + str + "</i>";
    }

}

How do I make this like the Python example above using a Java Annotation like this one:

public class Main {
    public static void main(String[] args) {
        @BoldWrapper
        @ItalicWrapper
        String str = "Hello World";
        // Display <b><i>Hello World</i></b>
    }
}

public @interface BoldWrapper {
    public void wrap() default "<b>" + str + "</b>";
}

public @interface ItalicWrapper {
    public void wrap() default "<i>" + str + "</i>";
}

I got some problem when I tried to make the sample, the problem is I don't know how I can pass the str value from the main method to the BoldWrapper and ItalicWrapper so it can concatenate and how to return it, so the main method can display the result that has been concatenate.

Please advise if there is something wrong with my understanding of annotation.

Kyr
  • 5,383
  • 2
  • 27
  • 22
Crazenezz
  • 3,416
  • 6
  • 31
  • 59
  • 3
    Nope, you're not going to be able to do this with annotations. – Louis Wasserman Aug 22 '12 at 02:53
  • Is there another way to make it with java without using the Decorator Design Pattern? – Crazenezz Aug 22 '12 at 02:54
  • You can do object decoration in Java just fine, but not with annotations. – Louis Wasserman Aug 22 '12 at 02:56
  • @LouisWasserman and what makes you think that this is impossible with annotations? That's exactly what they are for. – Strelok Aug 22 '12 at 02:59
  • 3
    Java annotations are compiled-metadata, accessible via refection. Frameworks can utilize attributes to provide functionality. But, nothing in the JVM/Java Libraries provides functionality for an attribute to indicate a decorating class (AOP Style). Nothing is stopping you from writing some sort of AOP framework that inspects for these annotations and provides the functionality you are wanting. But it would be a far cry different from what you have available in Python where you can transparently (to calling code) Decorate a method via an decorating annotation. – vossad01 Aug 22 '12 at 03:19

5 Answers5

6

If you are particularly interested in doing this kind of stuff with annotations (you don't have to really):

This example should get you started:

public class AnnotationTest
{
    @Target( ElementType.METHOD )
    @Retention( RetentionPolicy.RUNTIME )
    public static @interface TagWrapper
    {
        public String[] value() default {};
    }

    public static interface TextFragment
    {
        public String getText();
    }

    public static class TagWrapperProcessor
    {
        public static String getWrapperTextFragment( TextFragment fragment )
        {
            try
            {
                Method getText = fragment.getClass().getMethod( "getText" );
                TagWrapper tagWrapper = getText.getAnnotation( TagWrapper.class );
                String formatString = "<%s>%s</%s>";
                String result = ( String ) getText.invoke( fragment );
                for ( String tag : tagWrapper.value() )
                {
                    result = String.format( formatString, tag, result, tag );
                }
                return result;
            }
            catch ( Exception e )
            {
                throw new RuntimeException( e );
            }
        }
    }

    public static class BoldItalicFragment implements TextFragment
    {

        private String _text;

        public BoldItalicFragment( String text )
        {
            _text = text;
        }

        @Override
        @TagWrapper(
        {
            "b", "i"
        } )
        public String getText()
        {
            return _text;
        }

    }

    @Test
    public void testStuff()
    {
        System.out.println( TagWrapperProcessor.getWrapperTextFragment( new BoldItalicFragment( "Hello, World!" ) ) ); // prints: <i><b>Hello, World!</b></i>
    }
}
Strelok
  • 50,229
  • 9
  • 102
  • 115
4

This is late but I think it may help the other people. From Java 8 with Function interface, we can write something close to python decorator like this:

Function<Function<String, String>, Function<String, String>> makebold = func -> input -> "<b>" + func.apply(input) + "</b>";
Function<Function<String, String>, Function<String, String>> makeitalic = func -> input -> "<i>" + func.apply(input) + "</i>";

Function<String, String> helloWorld = input -> "hello world";
        System.out.println(makebold.apply(makeitalic.apply(helloWorld)).apply("")); // <b><i>hello world</i></b>
gianglaodai
  • 301
  • 1
  • 10
1

1) The link you cited is a good one - it does justice to the "Decorator Pattern" with respect to Java. "Design Patterns" themselves, of course, are independent of any particular OO language:

2) Here is another good link:

In Java, a classical example of the decorator pattern is the Java I/O Streams implementation.

FileReader       frdr = new FileReader(filename);
LineNumberReader lrdr = new LineNumberReader(frdr);

4) So yes, the "decorator pattern" is a good candidate for this problem.

Personally, I would prefer this kind of solution:

   String myHtml = 
     new BoldText (
       new ItalicText (
         new HtmlText ("See spot run")));

5) However annotations are also an option. For example:

Community
  • 1
  • 1
paulsm4
  • 114,292
  • 17
  • 138
  • 190
0

Although this doesn't resolve how to use annotations as you wanted, rather than using the "decorator design", I could propose you use the "builder design" if it suits better to your needs (it seems like so).

Quick usage example:

public class BuilderPatternExample {

    public static void main(String args[]) {

        //Creating object using Builder pattern in java
        Cake whiteCake = new Cake.Builder()
                                 .sugar(1)
                                 .butter(0.5)
                                 .eggs(2)
                                 .vanilla(2)
                                 .flour(1.5)
                                 .bakingPowder(0.75)
                                 .milk(0.5)
                                 .build();

        //Cake is ready to eat :)
        System.out.println(whiteCake);
    }
}

Output: Cake{sugar=0.75, butter=0.5, eggs=2, vanila=2, flour=1.5, bakingpowder=0.0, milk=0.5, cherry=0}

For full implementation and a very good explanation, please check http://javarevisited.blogspot.mx/2012/06/builder-design-pattern-in-java-example.html

DanielCuadra
  • 970
  • 9
  • 17
  • Thank you so much for the information, using the Builder Pattern is the key to solve the problem. But still I want to research more if possible to using Annotation to solve the problem. And I also aware that using annotation has side effect for the memory. – Crazenezz Apr 01 '14 at 05:15
0

Python decorators very like java annotation, but that are very different principle.

Annotations, a form of metadata, provide data about a program that is not part of the program itself. Annotations have no direct effect on the operation of the code they annotate.

But you can prosessing class file with bytecode enhancement. I make a simple project for implementing that approach. It using javassist processing class file after building. It searching methods with specified annotation in classes. And add bridge methods for calling between wrapped method and original method. It look like, calling bridgeMethod() -> wrapperMethod() -> originalMethod(). Your can reference from https://github.com/eshizhan/funcwraps.

eshizhan
  • 4,235
  • 2
  • 23
  • 23