KvantumObjectFactory { @SuppressWarnings("ALL") public static <T> KvantumObjectFactory<T> from(final Class<T> clazz) throws IllegalArgumentException { final KvantumObject kvantumObject; if ((kvantumObject = clazz.getAnnotation(KvantumObject.class)) == null) { throw new IllegalArgumentException(String .format("Class [%s] does not have an @KvantumObject annotation!", clazz.getName())); } if (factoryCache.containsKey(clazz)) { return (KvantumObjectFactory<T>) factoryCache.get(clazz); } final Map<String, InternalKvantumField> clazzFields = new LinkedHashMap<>(); KvantumField kvantumField; for (final Field field : clazz.getDeclaredFields()) { if ((kvantumField = field.getAnnotation(KvantumField.class)) != null) { final Optional<Parser<?>> parser = Parsers.getPrimitiveParser(field); if (!parser.isPresent()) { throw new IllegalArgumentException(String.format( "Failed to parse @KvantumField [{}]: " + "KvantumFields may not be of type [{}]", field.getName(), field.getType().getName())); } field.setAccessible(true); final String kvantumName; if (kvantumField.kvantumName().isEmpty()) { kvantumName = field.getName(); } else { kvantumName = kvantumField.kvantumName(); } final Object defaultValue; if (kvantumField.defaultValue().equals("null")) { defaultValue = null; } else { final ParserResult<?> parserResult = parser.get().parse(kvantumField.defaultValue()); if (parserResult.isParsed()) { defaultValue = parserResult.getResult(); } else { throw new IllegalArgumentException(String .format("Failed to parse @KvantumField [{}]: {}", field.getName(), parserResult.getError())); } } clazzFields.put(kvantumName, new InternalKvantumField(kvantumName, defaultValue, field, kvantumField, parser.get())); } } if (clazzFields.isEmpty()) { throw new IllegalArgumentException(String .format("Class [%s] does not have any @KvantumField annotations!", clazz.getName())); } final Set<InternalKvantumConstructorParameter> kvantumConstructorParameters = new LinkedHashSet<>(); Constructor<T> kvantumConstructor = null; for (final Constructor<?> constructor : clazz.getDeclaredConstructors()) { if (constructor.getAnnotation(KvantumConstructor.class) != null) { KvantumInsert insert; for (final Parameter parameter : constructor.getParameters()) { if ((insert = parameter.getAnnotation(KvantumInsert.class)) == null) { throw new IllegalArgumentException(String.format( "Class [%s] does not have an appropriate constructor (missing " + "@KvantumField for parameter (%s)", clazz.getName(), parameter.getName())); } final String fieldName = insert.value(); if (!clazzFields.containsKey(fieldName)) { throw new IllegalArgumentException(String.format( "Parameter '%s' in class '%s' is referring to kvantum field '%s'," + " but no such kvantum field is declared", parameter.getName(), clazz.getName(), fieldName)); } final InternalKvantumField field = clazzFields.get(fieldName); final Object defaultValue; if ("null".equals(insert.defaultValue())) { defaultValue = null; } else { final Parser<?> parser = field.getParser(); final ParserResult<?> parserResult = parser.parse(insert.defaultValue()); if (!parserResult.isParsed()) { throw new IllegalArgumentException(String.format( "Parameter '%s' in class '%s' is referring to kvantum field '%s'," + " but default value cannot be parsed: %s", parameter.getName(), clazz.getName(), fieldName, parserResult.getError())); } defaultValue = parserResult.getResult(); } final InternalKvantumConstructorParameter kvantumConstructorParameter = new InternalKvantumConstructorParameter(fieldName, field, defaultValue); kvantumConstructorParameters.add(kvantumConstructorParameter); } constructor.setAccessible(true); kvantumConstructor = (Constructor<T>) constructor; break; } } if (kvantumConstructor == null) { throw new IllegalArgumentException(String .format("Class [%s] does not have an appropriate constructor", clazz.getName())); } final val factory = new KvantumObjectFactory<>(kvantumObject, new InternalKvantumConstructor<>(kvantumConstructor, kvantumConstructorParameters), clazzFields); factoryCache.put(clazz, factory); return factory; }  @SuppressWarnings("ALL") static KvantumObjectFactory<T> from(final Class<T> clazz); BuilderInstance build(final ParameterScope scope);  }
@Test void from() { final KvantumObjectFactory<MockObject> factory = KvantumObjectFactory.from(MockObject.class); MockRequest mockRequest = new MockRequest(AbstractRequest.QueryCache.getInstance() .getQuery(new QueryParameters(HttpMethod.POST, ProtocolType.HTTP, "/?koala=animal"))); KvantumObjectParserResult<MockObject> result = factory.build(ParameterScope.GET).parseRequest(mockRequest); Assertions.assertNotNull(result); Assertions.assertTrue(result.isSuccess()); Assertions.assertNull(result.getError()); Assertions.assertNotNull(result.getParsedObject()); final MockObject mockObject = result.getParsedObject(); Assertions.assertEquals("animal", mockObject.string1); Assertions.assertEquals("york", mockObject.string2); mockRequest = new MockRequest(AbstractRequest.QueryCache.getInstance() .getQuery(new QueryParameters(HttpMethod.POST, ProtocolType.HTTP, "/?koala=a"))); result = factory.build(ParameterScope.GET).parseRequest(mockRequest); Assertions.assertNotNull(result); Assertions.assertFalse(result.isSuccess()); Assertions.assertNotNull(result.getError()); Assertions.assertNull(result.getParsedObject()); Assertions.assertTrue(result .getError() instanceof KvantumObjectParserResult.KvantumObjectParserValidationFailed); final KvantumObjectParserResult.KvantumObjectParserValidationFailed validationFailed = (KvantumObjectParserResult.KvantumObjectParserValidationFailed) result.getError(); Assertions.assertEquals(1, validationFailed.getViolations().size()); }