GenericClassSignatureParser { public ClassType parseGenericSignature() { String genericTypeName = genericSignature; String[] params = new String[0]; if(isValidGenericSignature()) { genericTypeName = genericSignature.substring(0, genericSignature.indexOf('<')); String parameters = genericSignature.substring(genericSignature.indexOf('<') + 1, genericSignature.lastIndexOf('>')); params = escapeNestedCommas(parameters).split(","); } String baseTypeName = baseType; String[] baseTypeParameters = null; if(baseType != null && baseType.contains("<")) { baseTypeName = baseType.substring(0, baseType.indexOf('<')); String baseTypeParameterString = baseType.substring(baseType.indexOf('<') + 1, baseType.lastIndexOf('>')); baseTypeParameters = escapeNestedCommas(baseTypeParameterString).split(","); } DataType baseDataType = resolveTypeName(baseTypeName); ClassType genericClassType = new ClassType(genericTypeName, baseDataType); for(String param: params) { TypeParameter paramType = handleParameterDeclaration(unescapeNestedCommas(param)); genericClassType.addGenericParameter(paramType); } if(baseTypeParameters != null) { int index = 0; for(String baseTypeParameter: baseTypeParameters) { if(baseTypeParameter.length() == 1 && genericClassType.getGenericParameterByIdentifier(baseTypeParameter) == null) { throw new RuntimeException("Cannot resolve symbol " + baseTypeParameter); } else{ DataType boundType = resolveTypeName(unescapeNestedCommas(baseTypeParameter)); ClassType baseTypeClass = (ClassType)baseDataType; List<ClassTypeElement> baseClassFields = baseTypeClass.getElements(); String myParam = baseTypeClass.getGenericParameters().get(index).getIdentifier(); System.out.println(boundType + " replaces param " + myParam); for(ClassTypeElement baseClassField : baseClassFields) { ClassTypeElement myElement = new ClassTypeElement(baseClassField.getName(), boundType); genericClassType.addElement(myElement); } } index++; } } return genericClassType; } GenericClassSignatureParser(String genericSignature, String baseType, String boundGenericTypeName, Map<String,DataType> resolvedTypes);  GenericClassSignatureParser(String genericSignature, Map<String,DataType> resolvedTypes); String getGenericSignature(); void setGenericSignature(String genericSignature); String getBaseType(); void setBaseType(String baseType); String getBoundGenericTypeName(); void setBoundGenericTypeName(String boundGenericTypeName); ClassType parseGenericSignature(); boolean isValidGenericSignature(); boolean isValidGenericSignature(String genericSignature); static final CharSequence OPEN_BRACKET; static final CharSequence CLOSE_BRACKET; static final String EXTENDS; }
@Test public void parseTest4() { try { ClassType collectionType = new ClassType("Collection", null, null); Map<String, DataType> resolvedTypes = new HashMap<>(); resolvedTypes.put("Collection", collectionType); GenericClassSignatureParser genericClassSignatureParser = new GenericClassSignatureParser("MyType<M constrains Collection>", resolvedTypes); genericClassSignatureParser.parseGenericSignature(); fail("Exception should be thrown for invalid parameter syntax"); } catch(Exception e) { assertThat(e.getMessage(), is("Invalid parameter syntax: M constrains Collection")); } }