1 /*
   2  * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.internal.ws.processor.modeler.annotation;
  27 
  28 import com.sun.codemodel.internal.CodeWriter;
  29 import com.sun.codemodel.internal.JAnnotationArrayMember;
  30 import com.sun.codemodel.internal.JAnnotationUse;
  31 import com.sun.codemodel.internal.JBlock;
  32 import com.sun.codemodel.internal.JCodeModel;
  33 import com.sun.codemodel.internal.JCommentPart;
  34 import com.sun.codemodel.internal.JDefinedClass;
  35 import com.sun.codemodel.internal.JDocComment;
  36 import com.sun.codemodel.internal.JExpr;
  37 import com.sun.codemodel.internal.JFieldVar;
  38 import com.sun.codemodel.internal.JMethod;
  39 import com.sun.codemodel.internal.JMod;
  40 import com.sun.codemodel.internal.JType;
  41 import com.sun.codemodel.internal.JVar;
  42 import com.sun.codemodel.internal.writer.ProgressCodeWriter;
  43 import com.sun.tools.internal.jxc.ap.InlineAnnotationReaderImpl;
  44 import com.sun.tools.internal.jxc.model.nav.ApNavigator;
  45 import com.sun.tools.internal.ws.ToolVersion;
  46 import com.sun.tools.internal.ws.processor.generator.GeneratorBase;
  47 import com.sun.tools.internal.ws.processor.generator.GeneratorConstants;
  48 import com.sun.tools.internal.ws.processor.generator.Names;
  49 import com.sun.tools.internal.ws.processor.modeler.ModelerException;
  50 import com.sun.tools.internal.ws.processor.util.DirectoryUtil;
  51 import com.sun.tools.internal.ws.resources.WebserviceapMessages;
  52 import com.sun.tools.internal.ws.util.ClassNameInfo;
  53 import com.sun.tools.internal.ws.wscompile.FilerCodeWriter;
  54 import com.sun.tools.internal.ws.wscompile.WsgenOptions;
  55 import com.sun.tools.internal.ws.wsdl.document.soap.SOAPStyle;
  56 import com.sun.xml.internal.bind.v2.model.annotation.AnnotationReader;
  57 import com.sun.xml.internal.bind.v2.model.nav.Navigator;
  58 import com.sun.xml.internal.ws.model.AbstractWrapperBeanGenerator;
  59 import com.sun.xml.internal.ws.spi.db.BindingHelper;
  60 import com.sun.xml.internal.ws.util.StringUtils;
  61 
  62 import javax.jws.Oneway;
  63 import javax.jws.WebMethod;
  64 import javax.jws.WebService;
  65 import javax.lang.model.element.ExecutableElement;
  66 import javax.lang.model.element.Name;
  67 import javax.lang.model.element.TypeElement;
  68 import javax.lang.model.type.DeclaredType;
  69 import javax.lang.model.type.MirroredTypeException;
  70 import javax.lang.model.type.TypeKind;
  71 import javax.lang.model.type.TypeMirror;
  72 import javax.xml.bind.annotation.XmlAccessType;
  73 import javax.xml.bind.annotation.XmlAccessorType;
  74 import javax.xml.bind.annotation.XmlAttachmentRef;
  75 import javax.xml.bind.annotation.XmlElement;
  76 import javax.xml.bind.annotation.XmlList;
  77 import javax.xml.bind.annotation.XmlMimeType;
  78 import javax.xml.bind.annotation.XmlRootElement;
  79 import javax.xml.bind.annotation.XmlType;
  80 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
  81 import javax.xml.namespace.QName;
  82 import javax.xml.ws.RequestWrapper;
  83 import javax.xml.ws.ResponseWrapper;
  84 import javax.xml.ws.WebFault;
  85 import javax.xml.ws.WebServiceException;
  86 import java.io.File;
  87 import java.io.IOException;
  88 import java.lang.annotation.Annotation;
  89 import java.util.Collection;
  90 import java.util.HashSet;
  91 import java.util.List;
  92 import java.util.Set;
  93 
  94 import static com.sun.codemodel.internal.ClassType.CLASS;
  95 import static com.sun.tools.internal.ws.processor.modeler.annotation.WebServiceConstants.BEAN;
  96 import static com.sun.tools.internal.ws.processor.modeler.annotation.WebServiceConstants.FAULT_INFO;
  97 import static com.sun.tools.internal.ws.processor.modeler.annotation.WebServiceConstants.JAXWS_PACKAGE_PD;
  98 import static com.sun.tools.internal.ws.processor.modeler.annotation.WebServiceConstants.PD_JAXWS_PACKAGE_PD;
  99 import static com.sun.tools.internal.ws.processor.modeler.annotation.WebServiceConstants.RESPONSE;
 100 
 101 /**
 102  * This class generates the request/response and Exception Beans
 103  * used by the JAX-WS runtime.
 104  *
 105  * @author  WS Development Team
 106  */
 107 public class WebServiceWrapperGenerator extends WebServiceVisitor {
 108     private Set<String> wrapperNames;
 109     private Set<String> processedExceptions;
 110     private JCodeModel cm;
 111     private final MakeSafeTypeVisitor makeSafeVisitor;
 112 
 113     private static final FieldFactory FIELD_FACTORY = new FieldFactory();
 114 
 115     private final AbstractWrapperBeanGenerator ap_generator =
 116             new ApWrapperBeanGenerator(InlineAnnotationReaderImpl.theInstance,
 117                     new ApNavigator(builder.getProcessingEnvironment()), FIELD_FACTORY);
 118 
 119     private final class ApWrapperBeanGenerator extends AbstractWrapperBeanGenerator<TypeMirror, TypeElement, ExecutableElement, MemberInfo> {
 120 
 121         protected ApWrapperBeanGenerator(
 122                 AnnotationReader<TypeMirror, TypeElement, ?, ExecutableElement> annReader,
 123                 Navigator<TypeMirror, TypeElement, ?, ExecutableElement> nav, BeanMemberFactory<TypeMirror, MemberInfo> beanMemberFactory) {
 124             super(annReader, nav, beanMemberFactory);
 125         }
 126 
 127         @Override
 128         protected TypeMirror getSafeType(TypeMirror type) {
 129             return WebServiceWrapperGenerator.this.getSafeType(type);
 130         }
 131 
 132         @Override
 133         protected TypeMirror getHolderValueType(TypeMirror paramType) {
 134             return builder.getHolderValueType(paramType);
 135         }
 136 
 137         @Override
 138         protected boolean isVoidType(TypeMirror type) {
 139             return type != null && type.getKind().equals(TypeKind.VOID);
 140         }
 141 
 142     }
 143 
 144     private static final class FieldFactory implements AbstractWrapperBeanGenerator.BeanMemberFactory<TypeMirror, MemberInfo> {
 145 
 146         @Override
 147         public MemberInfo createWrapperBeanMember(TypeMirror paramType,
 148                                                   String paramName, List<Annotation> jaxb) {
 149             return new MemberInfo(paramType, paramName, jaxb);
 150         }
 151     }
 152 
 153     public WebServiceWrapperGenerator(ModelBuilder builder, AnnotationProcessorContext context) {
 154         super(builder, context);
 155         makeSafeVisitor = new MakeSafeTypeVisitor(builder.getProcessingEnvironment());
 156     }
 157 
 158     @Override
 159     protected void processWebService(WebService webService, TypeElement d) {
 160         cm = new JCodeModel();
 161         wrapperNames = new HashSet<String>();
 162         processedExceptions = new HashSet<String>();
 163     }
 164 
 165     @Override
 166     protected void postProcessWebService(WebService webService, TypeElement d) {
 167         super.postProcessWebService(webService, d);
 168         doPostProcessWebService(webService, d);
 169     }
 170 
 171     @SuppressWarnings("CallToThreadDumpStack")
 172     protected void doPostProcessWebService(WebService webService, TypeElement d) {
 173         if (cm != null) {
 174             WsgenOptions options = builder.getOptions();
 175             assert options.filer != null;
 176             try {
 177                 CodeWriter cw = new FilerCodeWriter(options);
 178                 if(options.verbose)
 179                     cw = new ProgressCodeWriter(cw, System.out);
 180                 cm.build(cw);
 181             } catch (IOException e) {
 182                 e.printStackTrace();
 183             }
 184         }
 185     }
 186 
 187     @Override
 188     protected void processMethod(ExecutableElement method, WebMethod webMethod) {
 189         builder.log("WrapperGen - method: "+method);
 190         builder.log("method.getDeclaringType(): " + method.asType());
 191         if (wrapped && soapStyle.equals(SOAPStyle.DOCUMENT)) {
 192             generateWrappers(method, webMethod);
 193         }
 194         generateExceptionBeans(method);
 195     }
 196 
 197     private boolean generateExceptionBeans(ExecutableElement method) {
 198         String beanPackage = packageName + PD_JAXWS_PACKAGE_PD.getValue();
 199         if (packageName.length() == 0)
 200             beanPackage = JAXWS_PACKAGE_PD.getValue();
 201         boolean beanGenerated = false;
 202         for (TypeMirror thrownType : method.getThrownTypes()) {
 203             TypeElement typeDecl = (TypeElement) ((DeclaredType) thrownType).asElement();
 204             if (typeDecl == null) {
 205                 builder.processError(WebserviceapMessages.WEBSERVICEAP_COULD_NOT_FIND_TYPEDECL(
 206                         thrownType.toString(), context.getRound()));
 207                 return false;
 208             }
 209             boolean tmp = generateExceptionBean(typeDecl, beanPackage);
 210             beanGenerated = beanGenerated || tmp;
 211         }
 212         return beanGenerated;
 213     }
 214 
 215     private boolean duplicateName(String name) {
 216         for (String str : wrapperNames) {
 217             if (str.equalsIgnoreCase(name))
 218         return true;
 219         }
 220         wrapperNames.add(name);
 221     return false;
 222     }
 223 
 224     private boolean generateWrappers(ExecutableElement method, WebMethod webMethod) {
 225         boolean isOneway = method.getAnnotation(Oneway.class) != null;
 226         String beanPackage = packageName + PD_JAXWS_PACKAGE_PD.getValue();
 227         if (packageName.length() == 0)
 228             beanPackage = JAXWS_PACKAGE_PD.getValue();
 229         Name methodName = method.getSimpleName();
 230         String operationName = builder.getOperationName(methodName);
 231         operationName = webMethod != null && webMethod.operationName().length() > 0 ?
 232                 webMethod.operationName() : operationName;
 233         String reqName = operationName;
 234         String resName = operationName + WebServiceConstants.RESPONSE.getValue();
 235         String reqNamespace = typeNamespace;
 236         String resNamespace = typeNamespace;
 237 
 238         String requestClassName = beanPackage + StringUtils.capitalize(method.getSimpleName().toString());
 239         RequestWrapper reqWrapper = method.getAnnotation(RequestWrapper.class);
 240         if (reqWrapper != null) {
 241             if (reqWrapper.className().length() > 0)
 242                 requestClassName = reqWrapper.className();
 243             if (reqWrapper.localName().length() > 0)
 244                 reqName = reqWrapper.localName();
 245             if (reqWrapper.targetNamespace().length() > 0)
 246                 reqNamespace = reqWrapper.targetNamespace();
 247         }
 248         builder.log("requestWrapper: "+requestClassName);
 249 ///// fix for wsgen CR 6442344
 250         addGeneratedFile(requestClassName);
 251 //////////
 252         boolean canOverwriteRequest = builder.canOverWriteClass(requestClassName);
 253         if (!canOverwriteRequest) {
 254             builder.log("Class " + requestClassName + " exists. Not overwriting.");
 255         }
 256         if (duplicateName(requestClassName) && canOverwriteRequest) {
 257             builder.processError(WebserviceapMessages.WEBSERVICEAP_METHOD_REQUEST_WRAPPER_BEAN_NAME_NOT_UNIQUE(
 258                     typeElement.getQualifiedName(), method.toString()));
 259         }
 260 
 261         String responseClassName = null;
 262         boolean canOverwriteResponse = canOverwriteRequest;
 263         if (!isOneway) {
 264             responseClassName = beanPackage+StringUtils.capitalize(method.getSimpleName().toString())+RESPONSE.getValue();
 265             ResponseWrapper resWrapper = method.getAnnotation(ResponseWrapper.class);
 266             if(resWrapper != null) {
 267                 if (resWrapper.className().length() > 0)
 268                     responseClassName = resWrapper.className();
 269                 if (resWrapper.localName().length() > 0)
 270                     resName = resWrapper.localName();
 271                 if (resWrapper.targetNamespace().length() > 0)
 272                     resNamespace = resWrapper.targetNamespace();
 273             }
 274             canOverwriteResponse = builder.canOverWriteClass(responseClassName);
 275             if (!canOverwriteResponse) {
 276                 builder.log("Class " + responseClassName + " exists. Not overwriting.");
 277             }
 278             if (duplicateName(responseClassName) && canOverwriteResponse) {
 279                 builder.processError(WebserviceapMessages.WEBSERVICEAP_METHOD_RESPONSE_WRAPPER_BEAN_NAME_NOT_UNIQUE(
 280                         typeElement.getQualifiedName(), method.toString()));
 281             }
 282             addGeneratedFile(responseClassName);
 283         }
 284         //ArrayList<MemberInfo> reqMembers = new ArrayList<MemberInfo>();
 285         //ArrayList<MemberInfo> resMembers = new ArrayList<MemberInfo>();
 286         WrapperInfo reqWrapperInfo = new WrapperInfo(requestClassName);
 287         //reqWrapperInfo.setMembers(reqMembers);
 288         WrapperInfo resWrapperInfo = null;
 289         if (!isOneway) {
 290             resWrapperInfo = new WrapperInfo(responseClassName);
 291             //resWrapperInfo.setMembers(resMembers);
 292         }
 293         seiContext.setReqWrapperOperation(method, reqWrapperInfo);
 294         if (!isOneway)
 295             seiContext.setResWrapperOperation(method, resWrapperInfo);
 296         try {
 297             if (!canOverwriteRequest && !canOverwriteResponse) {
 298                 return false;
 299             }
 300 
 301             JDefinedClass reqCls = null;
 302             if (canOverwriteRequest) {
 303                 reqCls = getCMClass(requestClassName, CLASS);
 304             }
 305 
 306             JDefinedClass resCls = null;
 307             if (!isOneway && canOverwriteResponse) {
 308                 resCls = getCMClass(responseClassName, CLASS);
 309             }
 310 
 311             // XMLElement Declarations
 312             writeXmlElementDeclaration(reqCls, reqName,reqNamespace);
 313             writeXmlElementDeclaration(resCls, resName, resNamespace);
 314 
 315             List<MemberInfo> reqMembers = ap_generator.collectRequestBeanMembers(method);
 316             List<MemberInfo> resMembers = ap_generator.collectResponseBeanMembers(method);
 317 
 318             // XmlType
 319             writeXmlTypeDeclaration(reqCls, reqName, reqNamespace, reqMembers);
 320             writeXmlTypeDeclaration(resCls, resName, resNamespace, resMembers);
 321 
 322             // class members
 323             writeMembers(reqCls, reqMembers);
 324             writeMembers(resCls, resMembers);
 325 
 326         } catch (Exception e) {
 327             throw new ModelerException("modeler.nestedGeneratorError",e);
 328         }
 329         return true;
 330     }
 331 
 332     private void addGeneratedFile(String requestClassName) {
 333         File file = new File(DirectoryUtil.getOutputDirectoryFor(requestClassName, builder.getSourceDir()),
 334                 Names.stripQualifier(requestClassName) + GeneratorConstants.JAVA_SRC_SUFFIX.getValue());
 335         builder.getOptions().addGeneratedFile(file);
 336     }
 337 
 338 //    private List<Annotation> collectJAXBAnnotations(Declaration decl) {
 339 //        List<Annotation> jaxbAnnotation = new ArrayList<Annotation>();
 340 //        for(Class jaxbClass : jaxbAnns) {
 341 //            Annotation ann = decl.getAnnotation(jaxbClass);
 342 //            if (ann != null) {
 343 //                jaxbAnnotation.add(ann);
 344 //            }
 345 //        }
 346 //        return jaxbAnnotation;
 347 //    }
 348 
 349     private TypeMirror getSafeType(TypeMirror type) {
 350         return makeSafeVisitor.visit(type, builder.getProcessingEnvironment().getTypeUtils());
 351     }
 352 
 353     private JType getType(TypeMirror typeMirror) {
 354         String type = typeMirror.toString();
 355         try {
 356 //            System.out.println("typeName: "+typeName);
 357             return cm.parseType(type);
 358 //            System.out.println("type: "+type);
 359         } catch (ClassNotFoundException e) {
 360             return cm.ref(type);
 361         }
 362     }
 363 
 364     private void writeMembers(JDefinedClass cls, Collection<MemberInfo> members) {
 365         if (cls == null)
 366             return;
 367         for (MemberInfo memInfo : members) {
 368             JType type = getType(memInfo.getParamType());
 369             JFieldVar field = cls.field(JMod.PRIVATE, type, memInfo.getParamName());
 370             annotateParameterWithJaxbAnnotations(memInfo, field);
 371         }
 372         for (MemberInfo memInfo : members) {
 373             writeMember(cls, memInfo.getParamType(),
 374                     memInfo.getParamName());
 375         }
 376     }
 377 
 378     private void annotateParameterWithJaxbAnnotations(MemberInfo memInfo, JFieldVar field) {
 379         List<Annotation> jaxbAnnotations = memInfo.getJaxbAnnotations();
 380         for(Annotation ann : jaxbAnnotations) {
 381             if (ann instanceof XmlMimeType) {
 382                 JAnnotationUse jaxbAnn = field.annotate(XmlMimeType.class);
 383                 jaxbAnn.param("value", ((XmlMimeType)ann).value());
 384             } else if (ann instanceof XmlJavaTypeAdapter) {
 385                 JAnnotationUse jaxbAnn = field.annotate(XmlJavaTypeAdapter.class);
 386                 XmlJavaTypeAdapter ja = (XmlJavaTypeAdapter) ann;
 387                 try {
 388                     ja.value();
 389                     throw new AssertionError();
 390                 } catch (MirroredTypeException e) {
 391                     jaxbAnn.param("value",getType(e.getTypeMirror()));
 392                 }
 393                 // XmlJavaTypeAdapter.type() is for package only. No need to copy.
 394             } else if (ann instanceof XmlAttachmentRef) {
 395                 field.annotate(XmlAttachmentRef.class);
 396             } else if (ann instanceof XmlList){
 397                 field.annotate(XmlList.class);
 398             } else if (ann instanceof XmlElement) {
 399                 XmlElement elemAnn = (XmlElement)ann;
 400                 JAnnotationUse jAnn = field.annotate(XmlElement.class);
 401                 jAnn.param("name", elemAnn.name());
 402                 jAnn.param("namespace", elemAnn.namespace());
 403                 if (elemAnn.nillable()) {
 404                     jAnn.param("nillable", true);
 405                 }
 406                 if (elemAnn.required()) {
 407                      jAnn.param("required", true);
 408                 }
 409             } else {
 410                 throw new WebServiceException("SEI Parameter cannot have this JAXB annotation: " + ann);
 411             }
 412         }
 413     }
 414 
 415     protected JDefinedClass getCMClass(String className, com.sun.codemodel.internal.ClassType type) {
 416         JDefinedClass cls;
 417         try {
 418             cls = cm._class(className, type);
 419         } catch (com.sun.codemodel.internal.JClassAlreadyExistsException e){
 420             cls = cm._getClass(className);
 421         }
 422         return cls;
 423     }
 424 
 425     private boolean generateExceptionBean(TypeElement thrownDecl, String beanPackage) {
 426         if (!builder.isServiceException(thrownDecl.asType()))
 427             return false;
 428 
 429         String exceptionName = ClassNameInfo.getName(thrownDecl.getQualifiedName().toString());
 430         if (processedExceptions.contains(exceptionName))
 431             return false;
 432         processedExceptions.add(exceptionName);
 433         WebFault webFault = thrownDecl.getAnnotation(WebFault.class);
 434         String className = beanPackage+ exceptionName + BEAN.getValue();
 435 
 436         Collection<MemberInfo> members = ap_generator.collectExceptionBeanMembers(thrownDecl);
 437         boolean isWSDLException = isWSDLException(members, thrownDecl);
 438         String namespace = typeNamespace;
 439         String name = exceptionName;
 440         FaultInfo faultInfo;
 441         if (isWSDLException) {
 442             TypeMirror beanType =  getFaultInfoMember(members).getParamType();
 443             faultInfo = new FaultInfo(TypeMonikerFactory.getTypeMoniker(beanType), true);
 444             namespace = webFault.targetNamespace().length()>0 ?
 445                                webFault.targetNamespace() : namespace;
 446             name = webFault.name().length()>0 ?
 447                           webFault.name() : name;
 448             faultInfo.setElementName(new QName(namespace, name));
 449             seiContext.addExceptionBeanEntry(thrownDecl.getQualifiedName(), faultInfo, builder);
 450             return false;
 451         }
 452         if (webFault != null) {
 453             namespace = webFault.targetNamespace().length()>0 ?
 454                         webFault.targetNamespace() : namespace;
 455             name = webFault.name().length()>0 ?
 456                    webFault.name() : name;
 457             className = webFault.faultBean().length()>0 ?
 458                         webFault.faultBean() : className;
 459 
 460         }
 461         JDefinedClass cls = getCMClass(className, CLASS);
 462         faultInfo = new FaultInfo(className, false);
 463 
 464         if (duplicateName(className)) {
 465             builder.processError(WebserviceapMessages.WEBSERVICEAP_METHOD_EXCEPTION_BEAN_NAME_NOT_UNIQUE(
 466                     typeElement.getQualifiedName(), thrownDecl.getQualifiedName()));
 467         }
 468 
 469         boolean canOverWriteBean = builder.canOverWriteClass(className);
 470         if (!canOverWriteBean) {
 471             builder.log("Class " + className + " exists. Not overwriting.");
 472             seiContext.addExceptionBeanEntry(thrownDecl.getQualifiedName(), faultInfo, builder);
 473             return false;
 474         }
 475         if (seiContext.getExceptionBeanName(thrownDecl.getQualifiedName()) != null) {
 476             return false;
 477         }
 478 
 479         addGeneratedFile(className);
 480 
 481         //write class comment - JAXWS warning
 482         JDocComment comment = cls.javadoc();
 483         for (String doc : GeneratorBase.getJAXWSClassComment(ToolVersion.VERSION.MAJOR_VERSION)) {
 484             comment.add(doc);
 485         }
 486 
 487         // XmlElement Declarations
 488         writeXmlElementDeclaration(cls, name, namespace);
 489 
 490         // XmlType Declaration
 491         //members = sortMembers(members);
 492         XmlType xmlType = thrownDecl.getAnnotation(XmlType.class);
 493         String xmlTypeName = (xmlType != null && !xmlType.name().equals("##default")) ? xmlType.name() : exceptionName;
 494         String xmlTypeNamespace = (xmlType != null && !xmlType.namespace().equals("##default")) ? xmlType.namespace() : typeNamespace;
 495         writeXmlTypeDeclaration(cls, xmlTypeName, xmlTypeNamespace, members);
 496 
 497         writeMembers(cls, members);
 498 
 499         seiContext.addExceptionBeanEntry(thrownDecl.getQualifiedName(), faultInfo, builder);
 500         return true;
 501     }
 502 
 503     protected boolean isWSDLException(Collection<MemberInfo> members, TypeElement thrownDecl) {
 504         WebFault webFault = thrownDecl.getAnnotation(WebFault.class);
 505         return webFault != null && members.size() == 2 && getFaultInfoMember(members) != null;
 506     }
 507 
 508     /*
 509      * Returns the corresponding MemberInfo for getFaultInfo()
 510      * method of an exception. Returns null, if that method is not there.
 511      */
 512     private MemberInfo getFaultInfoMember(Collection<MemberInfo> members) {
 513         for(MemberInfo member : members) {
 514             if (member.getParamName().equals(FAULT_INFO.getValue())) {
 515                 return member;
 516             }
 517         }
 518         return null;
 519     }
 520 
 521     private void writeXmlElementDeclaration(JDefinedClass cls, String elementName, String namespaceUri) {
 522 
 523        if (cls == null)
 524             return;
 525         JAnnotationUse xmlRootElementAnn = cls.annotate(XmlRootElement.class);
 526         xmlRootElementAnn.param("name", elementName);
 527         if (namespaceUri.length() > 0) {
 528             xmlRootElementAnn.param("namespace", namespaceUri);
 529         }
 530         JAnnotationUse xmlAccessorTypeAnn = cls.annotate(cm.ref(XmlAccessorType.class));
 531         xmlAccessorTypeAnn.param("value", XmlAccessType.FIELD);
 532     }
 533 
 534     private void writeXmlTypeDeclaration(JDefinedClass cls, String typeName, String namespaceUri,
 535                                          Collection<MemberInfo> members) {
 536         if (cls == null)
 537             return;
 538         JAnnotationUse xmlTypeAnn = cls.annotate(cm.ref(XmlType.class));
 539         xmlTypeAnn.param("name", typeName);
 540         xmlTypeAnn.param("namespace", namespaceUri);
 541         if (members.size() > 1) {
 542             JAnnotationArrayMember paramArray = xmlTypeAnn.paramArray("propOrder");
 543             for (MemberInfo memInfo : members) {
 544                 paramArray.param(memInfo.getParamName());
 545             }
 546         }
 547     }
 548 
 549     private void writeMember(JDefinedClass cls, TypeMirror paramType,
 550                              String paramName) {
 551 
 552         if (cls == null)
 553             return;
 554 
 555         String accessorName =BindingHelper.mangleNameToPropertyName(paramName);
 556         String getterPrefix = paramType.toString().equals("boolean")? "is" : "get";
 557         JType propType = getType(paramType);
 558         JMethod m = cls.method(JMod.PUBLIC, propType, getterPrefix+ accessorName);
 559         JDocComment methodDoc = m.javadoc();
 560         JCommentPart ret = methodDoc.addReturn();
 561         ret.add("returns "+propType.name());
 562         JBlock body = m.body();
 563         body._return( JExpr._this().ref(paramName) );
 564 
 565         m = cls.method(JMod.PUBLIC, cm.VOID, "set"+accessorName);
 566         JVar param = m.param(propType, paramName);
 567         methodDoc = m.javadoc();
 568         JCommentPart part = methodDoc.addParam(paramName);
 569         part.add("the value for the "+ paramName+" property");
 570         body = m.body();
 571         body.assign( JExpr._this().ref(paramName), param );
 572     }
 573 }