// Path: src/main/java/com/moozvine/detox/processor/Util.java
// static boolean hasValueOfMethod(final TypeMirror value) {
//   if (!isClassOrInterface(value)) {
//     return false;
//   }
//   final DeclaredType declared = (DeclaredType) value;
//   final TypeElement typeElement = (TypeElement) declared.asElement();
//   for (final Element element : typeElement.getEnclosedElements()) {
//     if (element.getKind().equals(ElementKind.METHOD)) {
//       final ExecutableElement executableElement = (ExecutableElement) element;
//       if (executableElement.getSimpleName().toString().equals("valueOf")
//           && executableElement.getReturnType().toString().equals(value.toString())
//           && executableElement.getParameters().size() == 1
//           && executableElement.getParameters().get(0).asType().toString().equals("java.lang.String")) {
//         return true;
//       }
//     }
//   }
//   return false;
// }


import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.type.DeclaredType;
import javax.tools.JavaFileObject;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.List;
import static com.moozvine.detox.processor.Util.hasValueOfMethod;

            case COLLECTION:
              // TODO: Support collections of collections.
              throw new IllegalArgumentException("StringMaps of collections are not yet supported. Field: " +
                  member.getFieldName());

            default:
              throw new IllegalArgumentException("Cannot have a Map<String,T> with T of type " + mapMemberType
                  + ". Field: " + member.getFieldName());
          }

          w.append(String.format("" +
                  "      Map<%1$s, %2$s> %3$sBuilder = new HashMap<>();                            \n" +
                  "      if(json.has(\"%7$s\")) {                                                  \n" +
                  "        JSONObject %3$sObj = json.getJSONObject(\"%7$s\");                      \n" +
                  "        for(String key : (Set<String>)%3$sObj.keySet()) {                       \n" +
                  "          %3$sBuilder.put(%4$s,                                                 \n" +
                  "              %3$sObj.isNull(key) ? null : %6$s);                               \n" +
                  "        }                                                                       \n" +
                  "      }                                                                         \n" +
                  "      %3$s = Collections.unmodifiableMap(%3$sBuilder);                          \n" +
                  "                                                                                \n",
              stringMapType.getKeyType(), // 1
              mapMemberDeclaredType, // 2
              member.getFieldName(), // 3
              keyFromStringConverter, // 4
              "unused", // 5
              elementConverter, // 6
              member.getJsonFieldName() // 7
          ));
// Path: src/main/java/com/moozvine/detox/processor/Util.java
// static boolean hasValueOfMethod(final TypeMirror value) {
//   if (!isClassOrInterface(value)) {
//     return false;
//   }
//   final DeclaredType declared = (DeclaredType) value;
//   final TypeElement typeElement = (TypeElement) declared.asElement();
//   for (final Element element : typeElement.getEnclosedElements()) {
//     if (element.getKind().equals(ElementKind.METHOD)) {
//       final ExecutableElement executableElement = (ExecutableElement) element;
//       if (executableElement.getSimpleName().toString().equals("valueOf")
//           && executableElement.getReturnType().toString().equals(value.toString())
//           && executableElement.getParameters().size() == 1
//           && executableElement.getParameters().get(0).asType().toString().equals("java.lang.String")) {
//         return true;
//       }
//     }
//   }
//   return false;
// }


// Path: src/main/java/com/moozvine/detox/processor/DtoSynthesiser.java
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.type.DeclaredType;
import javax.tools.JavaFileObject;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.List;
import static com.moozvine.detox.processor.Util.hasValueOfMethod;


            case COLLECTION:
              // TODO: Support collections of collections.
              throw new IllegalArgumentException("StringMaps of collections are not yet supported. Field: " +
                  member.getFieldName());

            default:
              throw new IllegalArgumentException("Cannot have a Map<String,T> with T of type " + mapMemberType
                  + ". Field: " + member.getFieldName());
          }

          w.append(String.format("" +
                  "      Map<%1$s, %2$s> %3$sBuilder = new HashMap<>();                            \n" +
                  "      if(json.has(\"%7$s\")) {                                                  \n" +
                  "        JSONObject %3$sObj = json.getJSONObject(\"%7$s\");                      \n" +
                  "        for(String key : (Set<String>)%3$sObj.keySet()) {                       \n" +
                  "          %3$sBuilder.put(%4$s,                                                 \n" +
                  "              %3$sObj.isNull(key) ? null : %6$s);                               \n" +
                  "        }                                                                       \n" +
                  "      }                                                                         \n" +
                  "      %3$s = Collections.unmodifiableMap(%3$sBuilder);                          \n" +
                  "                                                                                \n",
              stringMapType.getKeyType(), // 1
              mapMemberDeclaredType, // 2
              member.getFieldName(), // 3
              keyFromStringConverter, // 4
              "unused", // 5
              elementConverter, // 6
              member.getJsonFieldName() // 7
          ));
        } else if (hasValueOfMethod(member.getTypeMirror())) {