View Javadoc

1   /****************************************************************************
2    * Copyright (c) 2005, 2006, 2007, 2008, 2009 Imola Informatica.
3    * All rights reserved. This program and the accompanying materials
4    * are made available under the terms of the LGPL License v2.1
5    * which accompanies this distribution, and is available at
6    * http://www.gnu.org/licenses/lgpl.html
7    ****************************************************************************/
8   package it.imolinfo.jbi4corba.webservice.generator.bcm;
9   
10  import it.imolinfo.jbi4corba.Logger;
11  import it.imolinfo.jbi4corba.LoggerFactory;
12  import it.imolinfo.jbi4corba.exception.ClassGenerationException;
13  import it.imolinfo.jbi4corba.webservice.generator.AnyType;
14  import it.imolinfo.jbi4corba.webservice.generator.InterfaceType;
15  import it.imolinfo.jbi4corba.webservice.generator.MethodSignature;
16  import it.imolinfo.jbi4corba.webservice.generator.Param;
17  import it.imolinfo.jbi4corba.webservice.generator.TypeUtils;
18  import it.imolinfo.jbi4corba.webservice.generator.UnionType;
19  import it.imolinfo.jbi4corba.webservice.generator.UnionTypeUtils;
20  import it.imolinfo.jbi4corba.webservice.generator.Util;
21  
22  import java.util.ArrayList;
23  import java.util.HashSet;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Set;
27  
28  import org.objectweb.asm.AnnotationVisitor;
29  import org.objectweb.asm.ClassAdapter;
30  import org.objectweb.asm.ClassVisitor;
31  import org.objectweb.asm.ClassWriter;
32  import org.objectweb.asm.MethodVisitor;
33  import org.objectweb.asm.Type;
34  
35  /**
36   * This class is used to add the annotations for the WebService. 
37   * Also collect the exceptions classes name thrown by the operation methods.
38   *
39   * FIXME with method overloading the behavior is undefined.
40   */
41  public class WebServiceAnnotationAdapter extends ClassAdapter {
42  
43      /**
44       * A JSR181 annotation internal class name.
45       * <pre>
46       * ==========================================================================
47       * member            | mean                              | default
48       * ==========================================================================
49       * name              | the name of the WS.               | Simple name of the
50       *                   | Used as the name of               | java class or
51       *                   | the wsdl:portType                 | interface.
52       * --------------------------------------------------------------------------
53       * targetNamespace   | used for wsdl:portType            | see JaxWs 2.0
54       *                   | or wsdl:service or both           |
55       * --------------------------------------------------------------------------
56       * serviceName       | wsdl:service (not allowed         | simple name of the
57       *                   | on endpoint interface)            | java class
58       *                   |                                   | + Service
59       * --------------------------------------------------------------------------
60       * portName          | wsdl:port (not allowed on         | WS name + Port
61       *                   | endpoint interface)               |
62       * --------------------------------------------------------------------------
63       * wsdlLocation      |                                   | none
64       * --------------------------------------------------------------------------
65       * endpointInterface | (not allowed on                   | none
66       *                   | endpoint interface)               |
67       * ==========================================================================
68       * </pre>
69       */
70      public static final String JSR181_WEB_SERVICE = "Ljavax/jws/WebService;";
71      private static final String W3CEPR = Type.getDescriptor(javax.xml.ws.wsaddressing.W3CEndpointReference.class);
72      /**
73       * A JSR181 annotation internal class name.
74       * <pre>
75       * ==========================================================================
76       * member            | mean                              | default
77       * ==========================================================================
78       * operationName     | wsdl:operation name               | name of the java
79       *                   |                                   | method
80       * --------------------------------------------------------------------------
81       * action            | the soap action                   | ""
82       * --------------------------------------------------------------------------
83       * exclude           | a method not exposed (not allowed | false
84       *                   | on endpoint interface)            |
85       * ==========================================================================
86       * </pre>
87       */
88      public static final String JSR181_WEB_METHOD = "Ljavax/jws/WebMethod;";
89      /**
90       * <pre>
91       * ==========================================================================
92       * member            | mean                              | default
93       * ==========================================================================
94       * name              | name of the parameter.            | WebMethod.operation
95       *                   |                                   | name if the
96       *                   | If RPC and WebParam.partName has  | operation is
97       *                   | not been specified, this is the   | DOCUMENT style and
98       *                   | name of the wsdl:part             | the parameter style
99       *                   |                                   | is BARE.
100      *                   | If DOCUMENT or the parameter maps |
101      *                   | to a header, this is the local    | Otherwise:
102      *                   | name of the XML element           | arg0,arg1,...
103      *                   | representing the parameter.       |
104      *                   |                                   |
105      *                   | A name MUST be specified if the   |
106      *                   | operation is DOCUMENT style, the  |
107      *                   | parameter style is BARE, and the  |
108      *                   | mode is OUT or INOUT.             |
109      * --------------------------------------------------------------------------
110      * partName          | the wsdl:part name.               | WebParam.name
111      *                   | Used only if the operation is RPC |
112      *                   | or the operation is DOCUMENT and  |
113      *                   | parameter style is BARE           |
114      * --------------------------------------------------------------------------
115      * mode              | the direction of the parameter    | INOUT if Holder
116      *                   | on endpoint interface)            | type otherwise IN
117      *                   |                                   | (see JaxWs 2.0)
118      * --------------------------------------------------------------------------
119      * header            | If true the parameter is pulled   | false
120      *                   | from a message header rather then |
121      *                   | the message body                  |
122      * ==========================================================================
123      * </pre>
124      */
125     public static final String JSR181_WEB_PARAM = "Ljavax/jws/WebParam;";
126     public static final String JSR181_WEB_PARAM_MODE = "Ljavax/jws/WebParam$Mode;";
127     public static final String JSR181_WEB_PARAM_MODE_INOUT = "INOUT";
128     public static final String JSR181_WEB_RESULT = "Ljavax/jws/WebResult;";
129     public static final String JAVAX_XML_WS_HOLDER_TYPE = "Ljavax/xml/ws/Holder;";
130     public static final String JAVAX_XML_WS_HOLDER_TYPE_CANONICAL_NAME = "javax.xml.ws.Holder";
131     public static final String JAVAX_XML_WS_HOLDER_TYPE_NO_SEMICOLON = "Ljavax/xml/ws/Holder";
132     public static final String JSR181_SOAP_BINDING = "Ljavax/jws/soap/SOAPBinding;";
133     public static final String JAXB_XML_SEE_ALSO_ANNOTATOIN = "Ljavax/xml/bind/annotation/XmlSeeAlso;";
134     public static final String JSR181_SOAP_BINDING_USE = "Ljavax/jws/soap/SOAPBinding$Use;";
135     public static final String JSR181_SOAP_BINDING_STYLE = "Ljavax/jws/soap/SOAPBinding$ParameterStyle;";
136     public static final String JSR181_LITERAL = "LITERAL";
137     public static final String JSR181_WRAPPED = "WRAPPED";
138     public static final String JSR181_BARE = "BARE";
139     private Map<String, UnionType> allUnionTypes;
140     private Map<String, InterfaceType> allInterfaceTypes;
141     private String workingDirClasses;
142     /* Exceptions list */
143     public Set<String> exceptionsThrown = new HashSet<String>();
144     /**
145      * Used to mark an asynchronous WebMethod.
146      */
147     public static final String JSR181_ONEWAY = "Ljavax/jws/Oneway;";
148     protected static Set<String> noAnnotatedMethods = new HashSet<String>();
149 
150 
151     static {
152         noAnnotatedMethods.add("<init>");
153         noAnnotatedMethods.add("hashCode");
154         noAnnotatedMethods.add("getClass");
155         noAnnotatedMethods.add("wait");
156         noAnnotatedMethods.add("equals");
157         noAnnotatedMethods.add("notify");
158         noAnnotatedMethods.add("notifyAll");
159         noAnnotatedMethods.add("toString");
160     }
161     /**
162      * Logger.
163      */
164     private static final Logger LOG = LoggerFactory.getLogger(WebServiceAnnotationAdapter.class);
165     /** The class writer for this bytecode manipulation. */
166     protected ClassWriter classWriter = null;
167     /** The list of method's signature. */
168     protected List<MethodSignature> methodSignatureList = null;
169     boolean areClassAnnotationsPresent = false;
170     /** The namespace */
171     protected String nameSpace = null;
172     /** The porttype  wsdl name */
173     protected String portTypeName = null;
174     /** All types  in idl */
175     protected Set<Class> allTypes = null;
176 
177     /**
178      * Constructor.
179      * 
180      * @param cv The class visitor.
181      * @param cw The class writer.
182      * @param aMethodSignatureList The list of method to manipulate.
183      * @param ns
184      * @param portTypeName if not null, the port type name
185      */
186     public WebServiceAnnotationAdapter(ClassVisitor cv, ClassWriter cw,
187             List<MethodSignature> aMethodSignatureList, String ns, String ptn, String workingDir, Map<String, UnionType> unionTypes, Map<String, InterfaceType> intfTypes, Set<Class> allTypesIDL) {
188 
189         super(cv);
190 
191         classWriter = cw;
192         methodSignatureList = aMethodSignatureList;
193         nameSpace = ns;
194         portTypeName = ptn;
195         allUnionTypes = unionTypes;
196         allInterfaceTypes = intfTypes;
197         workingDirClasses = workingDir;
198         allTypes = allTypesIDL;
199     }
200 
201     /**
202      * Override.
203      * @param version     The version
204      * @param access      The access
205      * @param name        The name
206      * @param signature   The signature
207      * @param superName   The super name
208      * @param interfaces  The interfaces
209      */
210     @Override
211     public void visit(int version, int access, String name, String signature,
212             String superName, String[] interfaces) {
213 
214         LOG.debug("CRB000605_WebServiceAnnotationAdapter_visit", new Object[]{version, access, name, signature, superName, interfaces});
215 
216         super.visit(version, access, name, signature, superName, interfaces);
217 
218         addAnnotation(name);
219 
220     }
221 
222     @Override
223     public void visitEnd() {
224 
225         cv.visitEnd();
226     }
227 
228     /**
229      * Adds the Webservice and SOAPBinding annotations
230      * @param name The service name
231      */
232     private void addAnnotation(String name) {
233         if (!areClassAnnotationsPresent) {
234 
235             // Adds the WebService annotation
236             AnnotationVisitor av = cv.visitAnnotation(JSR181_WEB_SERVICE, true);
237 
238             // If the port type is pspecified, uses it. Otherwise uses the java class name.
239             if (portTypeName != null) {
240                 LOG.debug("Adding port type name:" + portTypeName);
241                 av.visit("name", portTypeName);
242             } else {
243                 String javaSimpleName = name.substring(name.lastIndexOf("/") + 1);
244                 av.visit("name", javaSimpleName);
245             }
246             if (nameSpace != null) {
247                 av.visit("targetNamespace", nameSpace);
248                 LOG.debug("Adding targetNamespace:" + nameSpace);
249             }
250             if (av != null) {
251                 av.visitEnd();
252             }
253 
254             // Adds the SOAP annotation
255             AnnotationVisitor av2 = cv.visitAnnotation(JSR181_SOAP_BINDING, true);
256             av2.visitEnum("use", JSR181_SOAP_BINDING_USE, JSR181_LITERAL);
257             av2.visitEnum("parameterStyle",
258                     JSR181_SOAP_BINDING_STYLE, JSR181_WRAPPED);
259 
260 
261             if (av2 != null) {
262                 av2.visitEnd();
263             }
264 
265             // Adds the XMLSeeAlso annotation
266             AnnotationVisitor av3 = cv.visitAnnotation(JAXB_XML_SEE_ALSO_ANNOTATOIN, true);
267             AnnotationVisitor xmlElems = av3.visitArray("value");
268 
269             for (Class typeClass : allTypes) {
270                 String className = typeClass.getName();
271                 UnionType union = UnionTypeUtils.isUnionType(className, false, allUnionTypes);
272                 if (union != null) {
273                     try {
274                         typeClass = Util.classLoad(workingDirClasses, union.getTypeName() + "Wrapper");
275                     } catch (ClassGenerationException e) {
276                         //class not found ignoring
277                         LOG.debug("WebServiceAnnotationAdapter.addAnnotation: Class not found for union: " + union.getTypeName());
278                     }
279                 }
280 
281                 if (!Util.isThrowableSubClass(typeClass) && !typeClass.isInterface()) {
282 
283                     xmlElems.visit("value", Type.getType(typeClass));
284                     //Raf: added to manage jbi4corba-7 issue from nokia. To be removed if typedef defined type management is added
285                     //all idlj generated java primitive types are always added in the array version
286                     /*if (!typeClass.isArray() && !typeClass.isAnonymousClass() && !typeClass.isPrimitive()) {
287                         if (LOG.isDebugEnabled()){
288                         LOG.debug("orginal class: " + typeClass);
289                         LOG.debug("type descriptor: " + Type.getType(String.class).getDescriptor());
290                         LOG.debug("typeArray descriptor: " + Type.getType(String[].class).getDescriptor());
291                         LOG.debug("annotation for arrays: " + Type.getType("[" + Type.getType(typeClass).getDescriptor()));
292                         }
293                         //LOG.debug("annotation for arrays2: "+Type.getObjectType("["+typeClass.getCanonicalName()));
294                         xmlElems.visit("value", Type.getType("[" + Type.getType(typeClass).getDescriptor()));
295                     }*/
296                 }
297             }
298 
299             //Raf: added to manage jbi4corba-7 issue from nokia. To be removed if typedef defined type management is added
300             //all idlj generated java primitive types are always added in the array version            
301             /*
302             xmlElems.visit("value", Type.getType(boolean[].class));
303             xmlElems.visit("value", Type.getType(char[].class));
304             xmlElems.visit("value", Type.getType(byte[].class));
305             xmlElems.visit("value", Type.getType(String[].class));*/
306            
307             /*xmlElems.visit("value", Type.getType(short[].class));
308             xmlElems.visit("value", Type.getType(int[].class));
309             xmlElems.visit("value", Type.getType(long[].class));
310             xmlElems.visit("value", Type.getType(float[].class));
311             xmlElems.visit("value", Type.getType(double[].class));
312             xmlElems.visit("value", Type.getType(java.math.BigDecimal[].class));
313              */
314             //ISSUE 27
315             //xmlElems.visit("value", Type.getType(String[][].class));
316             if (xmlElems != null) {
317                 xmlElems.visitEnd();
318             }
319             if (av3 != null) {
320                 av3.visitEnd();
321             }
322 
323             areClassAnnotationsPresent = true;
324         }
325     }
326 
327     /**
328      * Override.
329      * @param access      The access
330      * @param name        The name
331      * @param desc        The desc
332      * @param signature   The signature
333      * @param exceptions  The exceptions
334      * @return            The return
335      */
336     @Override
337     public MethodVisitor visitMethod(int access, String name, String desc,
338             String signature, String[] exceptions) {
339 
340         LOG.debug("WebServiceAnnotationAdapter.visitMethod. access=" + access + "; name=" + name + "; desc=" + desc + "; signature=" + signature + "; exceptions=" + exceptions);
341 
342         if (exceptions != null) {
343             for (int i = 0; i < exceptions.length; i++) {
344                 LOG.debug("Exception found: " + exceptions[i]);
345                 exceptionsThrown.add(exceptions[i]);
346             }
347         }
348 
349         if (noAnnotatedMethods.contains(name)) {
350             LOG.debug("NO WebService Annotations [methodName=" + name + "]");
351             return super.visitMethod(access, name, desc, signature, exceptions);
352         }
353 
354         LOG.debug("WebService Annotations for [methodName=" + name + "]");
355 
356         // Gets the method visitor
357         MethodSignature methodSignature = findFirstMethodSignature(name);
358 
359         // Change the Holder parameter (if holder are present in the parameters.
360         //**********************************************************************
361         // INOUT
362 
363         if (methodSignature.isContainsHolder()) {
364             SignatureDescription sd = changeHolderParameters(methodSignature, desc, signature);
365             desc = sd.getDescription();
366             signature = sd.getSignature();
367         }
368         //**********************************************************************
369 
370 
371         MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
372 
373         addMethodSignatureAnnotation(mv, methodSignature, desc, signature);
374 
375         return mv;
376 
377     }
378 
379     /**
380      * Add annotation: WebMethod, Oneway, WebResult, WebParam.
381      * 
382      * @param methodVisitor The method visitor
383      * @param sig the Method Signature
384      * @param methodDescription the bytecode method description
385      */
386     protected void addMethodSignatureAnnotation(MethodVisitor methodVisitor,
387             MethodSignature methodSignature, String description, String signature) {
388 
389         addAnnotationOperationName(methodVisitor, methodSignature.getMethodName());
390 
391         // One-Way
392         if (methodSignature.isOneway()) {
393             LOG.debug("The method " + methodSignature.getMethodName() + " is marked 'oneway'.");
394             AnnotationVisitor avOneway = methodVisitor.visitAnnotation(JSR181_ONEWAY, true);
395             avOneway.visitEnd();
396         }
397 
398         addAnnotationReturnName(methodVisitor, methodSignature.getReturnName());
399 
400         addParameterAnnotation(methodVisitor, methodSignature);
401 
402     }
403 
404     /**
405      * This method is used to add the annotation to the method's parameters.
406      *
407      * @param    methodVisitor    The method visitor.
408      *                            If null the annotation is not added.
409      *
410      * @param    sig              The method's signature.
411      *                            If null the annotation is not added.
412      *
413      */
414     protected void addParameterAnnotation(MethodVisitor methodVisitor,
415             MethodSignature sig) {
416 
417         // check
418         if (methodVisitor == null) {
419             LOG.debug("The method visitor is null. add no annotation");
420             return;
421         }
422 
423         // check
424         if (sig == null) {
425             LOG.debug("The method's signature is null. add no annotation");
426             return;
427         }
428 
429         // check
430         if (sig.getParameters() == null || sig.getParameters().size() == 0) {
431 
432             LOG.debug("The list of parameter name is null or empty." + "add no annotation");
433             return;
434         }
435 
436 
437         LOG.debug("Adding parameter for the method: " + sig);
438         for (int pos = 0; pos < sig.getParameters().size(); pos++) {
439 
440             String param = sig.getParameters().get(pos).getName();
441             String paramType = sig.getParameters().get(pos).getTypeName();
442 
443             LOG.debug("Adding parameter name: " + param + " of type: " + paramType);
444 
445             AnnotationVisitor av = methodVisitor.visitParameterAnnotation(pos, JSR181_WEB_PARAM, true);
446             av.visit("name", param);
447 
448 
449             //av.visit("header", true); // default = false
450 
451             // If it's a Holder, adds the INOUT webparam mode
452             if (sig.getParameters().get(pos).isHolder()) {
453                 av.visitEnum("mode", JSR181_WEB_PARAM_MODE, JSR181_WEB_PARAM_MODE_INOUT);
454             }
455 
456             av.visitEnd();
457 
458             LOG.debug("WebParam annotation for [parameterName=" + param + "; parameterPosition=" + pos + "]");
459         }
460 
461 
462     }
463 
464     /**
465      * This method is used to add an annotation to customize the name of the
466      * return element.
467      *
468      * @param    methodVisitor    A method visitor.
469      *                            If null the annotation is not added.
470      *
471      * @param    returnName        The new name.
472      *                            If null or empty the annotation is not added.
473      */
474     protected void addAnnotationReturnName(MethodVisitor methodVisitor,
475             String returnName) {
476 
477         // check
478         if (methodVisitor == null) {
479             LOG.debug("The method visitor is null. add no annotation");
480             return;
481         }
482 
483         // check
484         if (returnName == null || "".equals(returnName)) {
485             LOG.debug("The return name is null or empty. add no annotation");
486             return;
487         }
488 
489         // annotation
490         AnnotationVisitor av = methodVisitor.visitAnnotation(JSR181_WEB_RESULT, true);
491 
492         av.visit("name", returnName);
493         av.visitEnd();
494 
495     }
496 
497     /**
498      * This method is used to add an annotation to customize the operation name.
499      *
500      * @param    methodVisitor    A method visitor.
501      *                            If null the annotation is not added.
502      *
503      * @param    operationName    The new operation name.
504      *                            If null or empty the annotation is not added.
505      *
506      */
507     protected void addAnnotationOperationName(MethodVisitor methodVisitor,
508             String operationName) {
509 
510         // check
511         if (methodVisitor == null) {
512             LOG.debug("The method visitor is null. add no annotation");
513             return;
514         }
515 
516         // check
517         if (operationName == null || "".equals(operationName)) {
518             LOG.debug("The operation name is null or empty. add no annotation");
519             return;
520         }
521 
522         // annotation
523         AnnotationVisitor av = methodVisitor.visitAnnotation(JSR181_WEB_METHOD, true);
524 
525         av.visit("operationName", operationName);
526         //avSig.visit("action", ""); // "" = default
527         av.visitEnd();
528     }
529 
530     /**
531      * Find a method.
532      *
533      * @param    methodName    The finding key.
534      *
535      * @return    The method signature of the first element with the name
536      *            in input. If the name is null or if the elemente does not exist
537      *            the method return null.
538      *
539      */
540     protected MethodSignature findFirstMethodSignature(String methodName) {
541         if (methodSignatureList == null) {
542             LOG.debug("Method's signature not found:" + "The list of the MethodSignature is null.");
543             return null;
544         }
545         // else
546         if (methodName == null) {
547             LOG.debug("Method's signature not found:" + "The method name is null.");
548             return null;
549         }
550         // else
551         for (MethodSignature sig : methodSignatureList) {
552             if (methodName.equals(sig.getMethodName())) {
553                 LOG.debug("MethodSignature FOUND. MethodName=" + methodName + "; MethodSignature=" + sig);
554                 return sig;
555             }
556         }
557         // else
558         LOG.debug("Method's signature not found for the method " + methodName);
559         return null;
560     }
561 
562     public Set<String> getExceptionsThrown() {
563         return exceptionsThrown;
564     }
565 
566     /**
567      * Changes the method description and signature to change the method interface.
568      * For example, the <br/>
569      *    public String test(org.omg.CORBA.StringHolder arg, String nogeneric) <br/>
570      *
571      * Must be changed in: <br/>
572      *
573      *    public String test(javax.xml.ws.Holder<String> arg, String nogeneric) <br/>
574      *
575      *  To do so, the description must change in: <br/>
576      *
577      *    (Ljavax/xml/ws/Holder;Ljava/lang/String;)Ljava/lang/String; <br/>
578      *
579      *  And the Signature must be not null and: <br/>
580      *
581      *    (Ljavax/xml/ws/Holder<Ljava/lang/String;>;Ljava/lang/String;)Ljava/lang/String; <br/>
582      *
583      *
584      * @param methodVisitor
585      * @param sig
586      * @param methodDescription
587      * @param methodSignature
588      */
589     protected SignatureDescription changeHolderParameters(MethodSignature sig, String methodDescription, String methodSignature) {
590 
591         StringBuffer newMethodDescription = new StringBuffer("(");
592         StringBuffer newMethodSignature = new StringBuffer("(");
593         InternalMethodDescriptionParser parser = new InternalMethodDescriptionParser(methodDescription);
594         List<String> internalParams = parser.parse();
595 
596         if (internalParams.size() != 0) {
597 
598             List<String> newParams = new ArrayList<String>();
599 
600 
601             // Change the Holder Corba type to java.xml.ws.Holder
602             for (int i = 0; i < sig.getParameters().size(); i++) {
603 
604                 Param param = (Param) sig.getParameters().get(i);
605                 if (param.isHolder()) {
606                     // Gets the paramt holder value type and converts it in the internal bytecode form.
607                     Class paramClass = param.getHolderValueType();
608                     String paramTypeDescriptor = Type.getDescriptor(paramClass);
609                     String holderValueTypeStr = TypeUtils.getTypeNameWithoutBrackets(paramClass);
610                     UnionType union = allUnionTypes.get(holderValueTypeStr);
611                     InterfaceType intf = allInterfaceTypes.get(holderValueTypeStr);
612 
613                     String arrayStr = TypeUtils.getArrayDimmentionAsPrefix(paramClass);
614                     boolean isAny = TypeUtils.getTypeNameWithoutBrackets(paramClass).equals(AnyType.CORBA_ANY_TYPE);
615 
616                     if (isAny) {
617                         paramTypeDescriptor = arrayStr + "Ljava/lang/Object;";
618                     }
619 
620                     if (intf != null) {
621                         paramTypeDescriptor = W3CEPR;
622                     }
623 
624                     if (union != null) {
625                         String wrapperType = null;
626                         try {
627                             wrapperType = UnionTypeUtils.createUnionClassWrapper(union, allUnionTypes, workingDirClasses);
628                             paramTypeDescriptor = arrayStr + "L" + wrapperType + ";";
629                         } catch (ClassGenerationException e) {
630                             LOG.error("Error generating wrapper class for uniontype:" + holderValueTypeStr);
631                         }
632                     }
633 
634                     LOG.debug("The parameter:" + param.getName() + "/" + param.getTypeName() + " is an Holder of type:" + paramTypeDescriptor);
635 
636                     // Sets the param  type  as javax.xml.ws.Holder
637                     newParams.add(JAVAX_XML_WS_HOLDER_TYPE);
638                     String newHolderParamName = JAVAX_XML_WS_HOLDER_TYPE_NO_SEMICOLON + "<" + paramTypeDescriptor + ">;";
639 
640                     // Sets javax.xml.Holder<class> as parameter type name.
641                     param.setTypeName(JAVAX_XML_WS_HOLDER_TYPE_CANONICAL_NAME + "<" + param.getHolderValueType().getCanonicalName() + ">");
642 
643                     // Adds the generic to the signature:
644                     newMethodSignature.append(newHolderParamName);
645 
646                 } else {
647                     // It's a "normal" (i mean no holder) parameter.
648                     newParams.add(internalParams.get(i));
649                     newMethodSignature.append(internalParams.get(i));
650                 }
651                 newMethodDescription.append(newParams.get(i));
652             }
653 
654             newMethodDescription.append(")").append(parser.getMethodDescriptionTail());
655             newMethodSignature.append(")").append(parser.getMethodDescriptionTail());
656           
657             // Reconstruct the correct method description
658             methodDescription = newMethodDescription.toString();
659             methodSignature = newMethodSignature.toString();
660         }
661 
662         return new SignatureDescription(methodDescription, methodSignature);
663     }
664 
665     /**
666      * Wrapper class for the description and signature of the analized methods
667      * @author marco
668      *
669      */
670     public class SignatureDescription {
671 
672         // method description
673         private String description;
674 
675         // method signature
676         private String signature;
677 
678         public SignatureDescription(String desc, String sig) {
679             description = desc;
680             signature = sig;
681         }
682 
683         public String getDescription() {
684             return description;
685         }
686 
687         public String getSignature() {
688             return signature;
689         }
690     }
691 }