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
26package com.sun.tools.internal.ws.processor.modeler.annotation;
27
28import com.sun.codemodel.internal.CodeWriter;
29import com.sun.codemodel.internal.JAnnotationArrayMember;
30import com.sun.codemodel.internal.JAnnotationUse;
31import com.sun.codemodel.internal.JBlock;
32import com.sun.codemodel.internal.JCodeModel;
33import com.sun.codemodel.internal.JCommentPart;
34import com.sun.codemodel.internal.JDefinedClass;
35import com.sun.codemodel.internal.JDocComment;
36import com.sun.codemodel.internal.JExpr;
37import com.sun.codemodel.internal.JFieldVar;
38import com.sun.codemodel.internal.JMethod;
39import com.sun.codemodel.internal.JMod;
40import com.sun.codemodel.internal.JType;
41import com.sun.codemodel.internal.JVar;
42import com.sun.codemodel.internal.writer.ProgressCodeWriter;
43import com.sun.tools.internal.jxc.ap.InlineAnnotationReaderImpl;
44import com.sun.tools.internal.jxc.model.nav.ApNavigator;
45import com.sun.tools.internal.ws.ToolVersion;
46import com.sun.tools.internal.ws.processor.generator.GeneratorBase;
47import com.sun.tools.internal.ws.processor.generator.GeneratorConstants;
48import com.sun.tools.internal.ws.processor.generator.Names;
49import com.sun.tools.internal.ws.processor.modeler.ModelerException;
50import com.sun.tools.internal.ws.processor.util.DirectoryUtil;
51import com.sun.tools.internal.ws.resources.WebserviceapMessages;
52import com.sun.tools.internal.ws.util.ClassNameInfo;
53import com.sun.tools.internal.ws.wscompile.FilerCodeWriter;
54import com.sun.tools.internal.ws.wscompile.WsgenOptions;
55import com.sun.tools.internal.ws.wsdl.document.soap.SOAPStyle;
56import com.sun.xml.internal.bind.v2.model.annotation.AnnotationReader;
57import com.sun.xml.internal.bind.v2.model.nav.Navigator;
58import com.sun.xml.internal.ws.model.AbstractWrapperBeanGenerator;
59import com.sun.xml.internal.ws.spi.db.BindingHelper;
60import com.sun.xml.internal.ws.util.StringUtils;
61
62import javax.jws.Oneway;
63import javax.jws.WebMethod;
64import javax.jws.WebService;
65import javax.lang.model.element.ExecutableElement;
66import javax.lang.model.element.Name;
67import javax.lang.model.element.TypeElement;
68import javax.lang.model.type.DeclaredType;
69import javax.lang.model.type.MirroredTypeException;
70import javax.lang.model.type.TypeKind;
71import javax.lang.model.type.TypeMirror;
72import javax.xml.bind.annotation.XmlAccessType;
73import javax.xml.bind.annotation.XmlAccessorType;
74import javax.xml.bind.annotation.XmlAttachmentRef;
75import javax.xml.bind.annotation.XmlElement;
76import javax.xml.bind.annotation.XmlList;
77import javax.xml.bind.annotation.XmlMimeType;
78import javax.xml.bind.annotation.XmlRootElement;
79import javax.xml.bind.annotation.XmlType;
80import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
81import javax.xml.namespace.QName;
82import javax.xml.ws.RequestWrapper;
83import javax.xml.ws.ResponseWrapper;
84import javax.xml.ws.WebFault;
85import javax.xml.ws.WebServiceException;
86import java.io.File;
87import java.io.IOException;
88import java.lang.annotation.Annotation;
89import java.util.Collection;
90import java.util.HashSet;
91import java.util.List;
92import java.util.Set;
93
94import static com.sun.codemodel.internal.ClassType.CLASS;
95import static com.sun.tools.internal.ws.processor.modeler.annotation.WebServiceConstants.BEAN;
96import static com.sun.tools.internal.ws.processor.modeler.annotation.WebServiceConstants.FAULT_INFO;
97import static com.sun.tools.internal.ws.processor.modeler.annotation.WebServiceConstants.JAXWS_PACKAGE_PD;
98import static com.sun.tools.internal.ws.processor.modeler.annotation.WebServiceConstants.PD_JAXWS_PACKAGE_PD;
99import 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 */
107public 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}
574