class UmpleToJava {
    class_PythonMethodDeclaration <<!<</*class_PythonMethodDeclaration*/>><<#

    if (uClass.hasMethods())
    {
      boolean hasQueued = false;
      for (Method aMethod : uClass.getMethods()) 
      {
        List<TraceItem> traceItems= aMethod.getTraced("method",uClass);

        if(!aMethod.getExistsInLanguage("Java") || aMethod.getSource() == Method.Source.fAutoAPI)
          continue;


        Position p = aMethod.getCodePosition();
        String positionHeader = "";        

        if (p != null) {
//        use annotations instead
        positionHeader = "  // line " + p.getLineNumber() + " \"" + uClass.getRelativePath(p.getFilename(),"Java") + "\"\n";
//        positionHeader = "\n  @umplesourcefile(line={"+p.getLineNumber()+"},file={\""+p.getFilename().replaceAll("\\\\","/").replaceAll("(.*)/","")+ "\"},javaline={"+(javaline+4)+"},length={"+(aMethod.getIsImplemented()?2: aMethod.getMethodBody().getExtraCode().split("\\n").length+2)+"})";          
        }
        else 
        {
          p = aMethod.getPosition();
//          positionHeader = "\n  @umplesourcefile(line={"+p.getLineNumber()+"},file={\""+p.getFilename().replaceAll("\\\\","/").replaceAll("(.*)/","")+ "\"},javaline={"+(javaline+3)+"},length={"+(aMethod.getIsImplemented()?2: aMethod.getMethodBody().getExtraCode().split("\\n").length+2)+"})";
        }
        String methodModifier = aMethod.getModifier().equals("") ? "public" : aMethod.getModifier();
        String methodImplementationModifier = aMethod.getIsAbstract() ? " abstract" : "";
        String methodName = aMethod.getName();
        String methodType = aMethod.getType();

        if(aMethod.getIsQueued())
        {
		  String isList="";
		  Boolean isFirstParameter = true;
		  if (aMethod.hasMethodParameters())
		  {
			append(realSb,"\n");
			append(realSb,"  public void {0} (",aMethod.getName());
			for (MethodParameter aMethodParam : aMethod.getMethodParameters()) 
			{
			  isList = aMethodParam.getIsList() ? " [] " : " ";
			  if (!isFirstParameter)
			  {
				append(realSb, ", ");
			  }
			  append(realSb, aMethodParam.getType() + isList + aMethodParam.getName());
			  isFirstParameter = false;
			}
			append(realSb, ");");

			append(realSb,"\n  {");

			append(realSb,"\n    Vector<Object> v = new Vector<Object>({0});", aMethod.numberOfMethodParameters());
			for ( int i=0; i < aMethod.numberOfMethodParameters(); i++)
			{
			  append(realSb,"\n    v.add({0}, {1});",i, aMethod.getMethodParameter(i).getName());
			}

			append(realSb,"\n    queuedMethodThread.putCallTo(queuedMethodThread.new QueuedMethodMessage(QueuedMethod.{0}", aMethod.getName());
			append(realSb,"_M, v));");
		  }
		  else
		  {
			append(realSb,"\n");
			append(realSb,"  public void ");
			append(realSb,"{0} ()",aMethod.getName());
			append(realSb,"\n  {");
			append(realSb,"\n    queuedMethodThread.putCallTo(queuedMethodThread.new QueuedMethodMessage(QueuedMethod.{0}",aMethod.getName());
			append(realSb,"_M, null));");
		  }
		  append(realSb,"\n  }");
		  append(realSb,"\n");
		  methodName = "_" + methodName;
		}

    // Fix issue 969
    if (!methodName.equals(uClass.getName()))
    {
      // If this is not a constructor, this method should return "void"
      methodType = methodType.equals("") ? "void" : methodType;
    }
    // handle mixsets inside methods(uClass, aMethod);
    mixset Mixset {
    ArrayList<MixsetInMethod> mixsetsWithinMethodList = aMethod.getMethodBody().getMixsetsWithinMethod();
    for(MixsetInMethod mixsetsWithinMethodItem : mixsetsWithinMethodList)
    {
      handelMixsetInsideMethod(model, mixsetsWithinMethodItem, aMethod.getMethodBody());
    }
    }
    // End 
    for(int i =uClass.getCodeInjections().size() ; i > 0 ; i--)
    {
      applyCodeInjectionToLabeledMethod(uClass, aMethod, "before");
      applyCodeInjectionToLabeledMethod(uClass, aMethod, "after");
      applyCodeInjectionToLabeledMethod(uClass, aMethod, "around");
    } 
        String customBeforeInjectionCode = GeneratorHelper.toCode(uClass.getApplicableCodeInjectionsCustomMethod("before", aMethod.getName(), aMethod.getMethodParameters()));
        String customAfterInjectionCode  = GeneratorHelper.toCode(uClass.getApplicableCodeInjectionsCustomMethod("after", aMethod.getName(), aMethod.getMethodParameters()));
        if( (customBeforeInjectionCode != null) && (customAfterInjectionCode == null) )
        {
          if(customBeforeInjectionCode.contains("around_proceed:"))
          {
            String[] codeToInjectArray = customBeforeInjectionCode.split("around_proceed:");
            customBeforeInjectionCode = codeToInjectArray[0];
            customAfterInjectionCode = ""+codeToInjectArray[1];
            customAfterInjectionCode = customAfterInjectionCode.replace("END OF UMPLE BEFORE INJECTION","END OF UMPLE AROUND INJECTION");
          }
        }

        String customPreconditionCode = GeneratorHelper.toCode(uClass.getApplicableCodeInjections("before", aMethod.getName()+"Precondition"));        
        String customPostconditionCode = GeneratorHelper.toCode(uClass.getApplicableCodeInjections("before", aMethod.getName()+"Postcondition"));
        customPostconditionCode = customPostconditionCode==null?"":customPostconditionCode;

        String methodBody = aMethod.getIsImplemented() ? "      return " + gen.translate(methodType) + ";" : "<TXL UGM>\n\t\t" + aMethod.getMethodBody().getExtraCode() + "\n\t\t</TXL UGM>";
        String properMethodBody = "    " + methodBody; 
        String override =  aMethod.getIsImplemented() ? "  @Override\n" : "";
        String paramName="";
        String paramType="";
        String aSingleParameter="";
        String isList="";
        String finalParams = "";        
        String finalParamsWithoutTypes = "";
        StringBuilder parameters = new StringBuilder();
        StringBuilder parametersWithoutTypes = new StringBuilder();
        if (aMethod.hasMethodParameters())
        {
          for (MethodParameter aMethodParam : aMethod.getMethodParameters()) 
          {
            paramName = aMethodParam.getName();
            paramType = aMethodParam.getType();
            isList = aMethodParam.getIsList() ? " [] " : " ";
            aSingleParameter = paramType + isList + paramName;
            parameters.append(aSingleParameter + ", ");
            parametersWithoutTypes.append(aMethodParam.getName() + ", ");
          }

          finalParams = parameters.toString().substring(0, parameters.toString().length()-2);
          finalParamsWithoutTypes = parametersWithoutTypes.toString().substring(0, parametersWithoutTypes.toString().length()-2);
        }

        /*
        to change the name of the user defined constructors
        */
        if(uClass.getHasProxyPattern()||(uClass.getNeedsDefaultInterface()&&model.getDistributePattern()>0))
        {
          if(("".equals(methodType))&&(uClass.getName().equals(methodName+"Impl")))
          {
            methodName+="Impl";
          }
        }

        if(methodName.equals("main")&&methodType.equals("void")&&methodModifier.contains("public")&&methodModifier.contains("static")
          &&paramType.equals("String")&&isList.equals(" [] "))
        {
          String exceptionHandlerPackage = "";
          if(model.getMainClass() != null)
          {
            if (model.getMainClass().getPackageName() != "")  exceptionHandlerPackage = model.getMainClass().getPackageName() + ".";

            exceptionHandlerPackage += model.getMainClass().getName()+".";
          }
          else
          {
            model.setMainClass(uClass);
          }
          properMethodBody = "    Thread.currentThread().setUncaughtExceptionHandler(new "+exceptionHandlerPackage+"UmpleExceptionHandler());\n"+
                             "    Thread.setDefaultUncaughtExceptionHandler(new "+exceptionHandlerPackage+"UmpleExceptionHandler());\n"+properMethodBody;
          uClass.setHasMainMethod(true);
        }
        if (aMethod.numberOfComments() > 0 && aMethod.numberOfRequirements() > 0) { List<Comment> toComment = new ArrayList<Comment>(aMethod.getComments()); toComment.addAll(Requirement.convertToComment(aMethod.getRequirements())); append(realSb, "\n\n  {0}", Comment.format("Method Javadoc", toComment)); }
        else if (aMethod.numberOfComments() > 0) { append(realSb, "\n\n  {0}", Comment.format("Method Javadoc",aMethod.getComments())); }
        else if (aMethod.numberOfRequirements() > 0) { append(realSb, "\n\n  {0}", Requirement.format("Method Javadoc",aMethod.getRequirements())); }

        append(realSb,"\n");
        int javaline = realSb.toString().split("\\n").length+(aMethod.numberOfComments() > 0?0:1);

        StringBuilder methodExceptionsBuilder = new StringBuilder();
        if(aMethod.getExceptions()!=null&&aMethod.numberOfExceptions()>0)
        {
          methodExceptionsBuilder.append(" throws ");
          String exceptioncomma = "";
          for(String methodException:aMethod.getExceptions())
          {
            if(!"".equals(methodException))
            {
              methodExceptionsBuilder.append(exceptioncomma);
              methodExceptionsBuilder.append(methodException);
              exceptioncomma = ",";
            }
          }
        }
        String methodExceptions = methodExceptionsBuilder.toString();

        if(!"".equals(customPostconditionCode))
        {
          StringBuilder lineNumbers = new StringBuilder();
          StringBuilder javaLineNumbers = new StringBuilder();
          StringBuilder filenames = new StringBuilder();
          StringBuilder lengths = new StringBuilder();
          String comma = "";
          if(p!=null)
          {
            int previousConditionsFound = 0;
            for(Postcondition condition:uClass.getPostConds())
            {
              if(condition.getMethod().equals(aMethod)&&condition.getPosition()!=null)
              {
                lineNumbers.append(comma+(condition.getPosition().getLineNumber()));
                filenames.append(comma+condition.getPosition().getFilename());
                javaLineNumbers.append(comma+(javaline+7+3*previousConditionsFound));
                lengths.append(comma+"1");
                comma = ",";
                previousConditionsFound++;
              }
            }
          }
          if(!"".equals(lineNumbers.toString())){
            String positionEndHeader = "\n";
          }

          append(realSb,positionHeader);
          append(realSb,override);
          append(realSb, "{5}  {0}{1} {2} {3}({4}){6}", methodModifier, methodImplementationModifier, methodType, methodName, finalParams, positionHeader, methodExceptions);

          appendln(realSb, "{");
          if(!"".equals(methodType)&&!"void".equals(methodType))
          {
            append(realSb, "    {0} result = {1}_Original({2});\n", methodType, methodName, finalParamsWithoutTypes);
          }
          else
          {
            append(realSb, "    {0}_Original({1});\n", methodName, finalParamsWithoutTypes);
          }
          addUncaughtExceptionVariables(realSb.toString().split("\\n").length,customPostconditionCode,methodName);
          appendln(realSb, GeneratorHelper.doIndent(customPostconditionCode, "    "));
          if(!"".equals(methodType)&&!"void".equals(methodType))
          {
            append(realSb, "    return result;\n");
            javaline++;
          }          
          appendln(realSb, "  }");

          javaline+= 5+customPostconditionCode.split("\\n").length;
          append(realSb, "\n  {0}{1} {2} {3}_Original({4}){5}", methodModifier, methodImplementationModifier, methodType, methodName, finalParams, methodExceptions);
        }
        else
        {
          append(realSb,override);
          append(realSb, "{5}  {0}{1} {2} {3}({4}){6}", methodModifier, methodImplementationModifier, methodType, methodName, finalParams, positionHeader, methodExceptions);
        }
        if(aMethod.getIsAbstract())
        {
          append(realSb, ";\n");
        }
        else
        {
          appendln(realSb, "{");
          for( TraceItem traceItem : traceItems )append(realSb, (traceItem!=null&&traceItem.getIsPre()?traceItem.trace(gen, aMethod,"me_e", uClass):""));
          if (customPreconditionCode != null) {
            addUncaughtExceptionVariables(realSb.toString().split("\\n").length,customPreconditionCode,methodName);
            append(realSb, "\n{0}\n",GeneratorHelper.doIndent(customPreconditionCode, "    "));
          }
          if (customBeforeInjectionCode != null) {
            addUncaughtExceptionVariables(realSb.toString().split("\\n").length,customBeforeInjectionCode,methodName);
            append(realSb, "{0}\n",GeneratorHelper.doIndent(customBeforeInjectionCode, "    "));
            aMethod.getMethodBody().getCodeblock().setCode("", GeneratorHelper.doIndent(customBeforeInjectionCode, "    ") + aMethod.getMethodBody().getCodeblock());
        }

          String traceCode = "";
          if(properMethodBody.contains("return"))
          {
            for( TraceItem traceItem : traceItems )traceCode += (traceItem!=null&&traceItem.getIsPost()?traceItem.trace(gen, aMethod,"me_x", uClass):"");
              properMethodBody = properMethodBody.replaceAll("return", traceCode + "return");

            if(customAfterInjectionCode != null) {
              // Do some pre-processing to handle returns not being on a new line. Doing this allows us to maintain suitable indentation.
              String[] properMethodLines = properMethodBody.split("\\n");
              String fixedProperMethodBody = "";
              for(int i = 0; i < properMethodLines.length; i++) {
                if(GeneratorHelper.isValidReturnStatement(properMethodLines[i]) && !properMethodLines[i].trim().substring(0, 6).equals("return")) {
                  String[] splitLines = properMethodLines[i].split("return", 2); 
                  // Determine indentation of return by adding indentation amount to previous line
                  String returnIndent = "";
                  int j = 0;
                  while(splitLines[0].charAt(j) == ' ') {
                    returnIndent += " ";
                    j++;
                  }

                  fixedProperMethodBody += returnIndent + splitLines[0].trim() + "\n";

                  String[] returnLines = splitLines[1].split(";");
                  if(returnLines.length > 1 && returnLines[1].trim().length() > 0) {
                    fixedProperMethodBody += returnIndent + "  return " + returnLines[0].trim() + ";\n" + returnIndent + returnLines[1].trim() + "\n"; 
                  } else {
                    fixedProperMethodBody += returnIndent + "  return " + splitLines[1].trim() + "\n"; 
                  }
                } else {
                  fixedProperMethodBody += properMethodLines[i] + "\n";
                }
              }

              properMethodBody = fixedProperMethodBody;

              String properMethodIndent = "";
              int indentIndex = 0;
              while(indentIndex < properMethodBody.length() && properMethodBody.charAt(indentIndex) == ' ') {
                properMethodIndent += " ";
                indentIndex++;
              }

              // inject the after injection code after every return, while appropriate indentation
              List<Integer> injectedLineNumbers = new ArrayList<Integer>();
              for(int i = -1; (i = properMethodBody.indexOf("return", i + 1)) != -1; ) {
              	//Check if return statement is on its own line
              	int lastChar = i - 1;
              	while (lastChar != -1 && properMethodBody.charAt(lastChar) == ' ')
              	  lastChar--;
              	if (lastChar == -1  || properMethodBody.charAt(lastChar) != '\n') // If it has any non-space characters before it, it's invalid
              	  continue;

                // determine the indentation of the return
                String indent = "";
                while(i >= 1 && properMethodBody.charAt(--i) == ' ') {
                  indent += " ";
                }

                // Need to determine if block has braces surrounding it. To do this, take the previous
                // lines of code and apply some regex to remove all of the comments.
                String[] previousLinesOfCode = properMethodBody.substring(0, i+1).replaceAll("\\/\\*([\\S\\s]+?)\\*\\/", "").replaceAll("(?s)/\\*.*?\\*/", "").replaceAll("//.*$", "").split("\\n");
                int commentLineCount = properMethodBody.substring(0, i+1).split("\\n").length - previousLinesOfCode.length;

                // set previousLine to be the first non-empty line
                int previousLine = -1; 
                for(int j = previousLinesOfCode.length - 1; j >= 0; j--) {
                  if(previousLinesOfCode[j].trim().length() > 0) {
                    previousLine = j;
                    break;
                  }
                }

                String previousLineStr = previousLinesOfCode[previousLine].trim();

                // Need to subtract the number of lines of comments between the return and the previous line of code
                while(!properMethodBody.split("\\n")[previousLine + commentLineCount].trim().equals(previousLineStr)) {
                  commentLineCount--;
                }

                // If we need to, insert braces, otherwise continue as normal
                String indentedCustomAfterInjectionCode = GeneratorHelper.doIndent("\n" + customAfterInjectionCode, indent);
                String braceIndent = "";
                String brace = "";
                String braceNewLine = "";
                if(previousLine != -1 && (previousLineStr.charAt(previousLineStr.length()-1) == ')' || (previousLineStr.length() >= 4 && previousLineStr.substring(previousLineStr.length()-4).equals("else")))) {
                  String[] methodLines = properMethodBody.split("\\n");
                  previousLine += commentLineCount;

                  // determine how indented the brace is
                  int j = 0;
                  while(j < methodLines[previousLine].length() && methodLines[previousLine].charAt(j) == ' ') {
                    braceIndent += " ";
                    j++;
                  }

                  methodLines[previousLine] = braceIndent + methodLines[previousLine].trim() + " {"; 

                  // Set properMethodBody to be String.join(methodLines, "\\n")
                  String newProperMethodBody = "";
                  for(int k = 0; k < methodLines.length; k++) {
                    newProperMethodBody += methodLines[k];
                    if(k != methodLines.length - 1) {
                      newProperMethodBody += "\n";
                    }
                  }
                  properMethodBody = newProperMethodBody;

                  brace = "}";
                  braceNewLine = "\n";
                }

                i += indent.length() + 1;
                String[] returnAndRest = properMethodBody.substring(i).split(";", 2);
                injectedLineNumbers.add(properMethodBody.substring(0, i).trim().split("\\n").length);
                properMethodBody = properMethodIndent + properMethodBody.substring(0, i).trim() + indentedCustomAfterInjectionCode + "\n" + indent + returnAndRest[0].trim() + ";" + braceNewLine + braceIndent + brace + returnAndRest[1]; 
                i += indentedCustomAfterInjectionCode.length() + braceIndent.length() + 7;
              }

              // if the last line isn't a return, insert the injection at the very end
              String[] lines = properMethodBody.split("\\n");
              if(!lines[lines.length-1].contains("return")) {
                injectedLineNumbers.add(lines.length);
                properMethodBody += GeneratorHelper.doIndent("\n" + customAfterInjectionCode, "    ");
              }

              int javaLength = realSb.toString().split("\\n").length;
              for (Integer line : injectedLineNumbers) {
                addUncaughtExceptionVariables(javaLength + line,customAfterInjectionCode,methodName);
              }
            }
          }
          appendln(realSb, properMethodBody);
          if(!properMethodBody.contains("return"))
          {
            for( TraceItem traceItem : traceItems )append(realSb, (traceItem!=null&&traceItem.getIsPost()?traceItem.trace(gen, aMethod,"me_x", uClass):""));
            if (customAfterInjectionCode != null) {
                addUncaughtExceptionVariables(realSb.toString().split("\\n").length,customAfterInjectionCode,methodName);
                append(realSb, "{0}\n",GeneratorHelper.doIndent(customAfterInjectionCode, "    "));
            }
          }
          appendln(realSb, "  }");
          addUncaughtExceptionVariables(methodName,p.getFilename().replaceAll("\\\\","/").replaceAll("(.*)/",""),p.getLineNumber(),javaline,methodBody.split("\\n").length);
        }

      }
    }
#>>!>>
}