Skip to content

Commit a2d8f13

Browse files
committed
ConfigInstanceBuilder support @WithConverter
1 parent 000969c commit a2d8f13

3 files changed

Lines changed: 271 additions & 54 deletions

File tree

implementation/src/main/java/io/smallrye/config/ConfigInstanceBuilderImpl.java

Lines changed: 27 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ private static void registerConverters() {
333333
}
334334

335335
@SuppressWarnings("unchecked")
336-
private static <T> Converter<T> getConverter(Class<T> type) {
336+
public static <T> Converter<T> getConverter(Class<T> type) {
337337
Converter<?> exactConverter = CONVERTERS.get(type);
338338
if (exactConverter != null) {
339339
return (Converter<T>) exactConverter;
@@ -342,58 +342,49 @@ private static <T> Converter<T> getConverter(Class<T> type) {
342342
return (Converter<T>) getConverter(Converters.wrapPrimitiveType(type));
343343
}
344344
if (type.isArray()) {
345-
final Converter<?> conv = getConverter(type.getComponentType());
346-
return conv == null ? null : Converters.newArrayConverter(conv, type);
345+
Converter<?> conv = getConverter(type.getComponentType());
346+
if (conv != null) {
347+
return Converters.newArrayConverter(conv, type);
348+
}
349+
throw ConfigMessages.msg.noRegisteredConverter(type);
347350
}
348351

349-
return Implicit.getConverter(type);
350-
}
351-
352-
public static <T> T convertValue(final String value, final Class<T> type) {
353-
Converter<T> converter = getConverter(type);
352+
Converter<T> converter = Implicit.getConverter(type);
354353
if (converter == null) {
355-
throw new IllegalArgumentException("No converter found for type " + type);
354+
throw ConfigMessages.msg.noRegisteredConverter(type);
356355
}
357-
return converter.convert(value);
356+
return converter;
358357
}
359358

360-
public static <T> Optional<T> convertOptionalValue(final String value, final Class<T> type) {
361-
Converter<T> converter = getConverter(type);
362-
if (converter == null) {
363-
throw new IllegalArgumentException("No converter found for type " + type);
359+
public static <T> T convertValue(final String value, final Converter<T> converter) {
360+
T convert = converter.convert(value);
361+
if (convert == null) {
362+
// TODO - new messsage instead of reuse?
363+
throw ConfigMessages.msg.converterReturnedNull("", value, converter.getClass().getTypeName());
364364
}
365-
return Converters.newOptionalConverter(converter).convert(value);
365+
return convert;
366366
}
367367

368-
public static <T, C extends Collection<T>> C convertValues(
369-
final String value,
370-
final Class<T> itemType,
371-
final Class<C> collectionType) {
372-
return convertValues(value, itemType, createCollectionFactory(collectionType));
368+
public static <T> Optional<T> convertOptionalValue(final String value, final Converter<T> converter) {
369+
return convertValue(value, Converters.newOptionalConverter(converter));
373370
}
374371

375372
@SuppressWarnings("unchecked")
376-
public <T, C extends Collection<T>> Optional<C> convertOptionalValues(
373+
public static <T, C extends Collection<T>> C convertValues(
377374
final String value,
378-
final Class<T> itemType,
379-
final IntFunction<? extends Collection<T>> collectionFactory) {
380-
Converter<T> converter = getConverter(itemType);
381-
if (converter == null) {
382-
throw new IllegalArgumentException("No converter found for type " + itemType);
383-
}
384-
return (Optional<C>) newOptionalConverter(newCollectionConverter(converter, collectionFactory)).convert(value);
375+
final Converter<T> converter,
376+
final Class<C> collectionType) {
377+
return (C) convertValue(value, newCollectionConverter(converter, createCollectionFactory(collectionType)));
385378
}
386379

387380
@SuppressWarnings("unchecked")
388-
public static <T, C extends Collection<T>> C convertValues(
381+
public static <T, C extends Collection<T>> Optional<C> convertOptionalValues(
389382
final String value,
390-
final Class<T> itemType,
391-
final IntFunction<? extends Collection<T>> collectionFactory) {
392-
Converter<T> converter = getConverter(itemType);
393-
if (converter == null) {
394-
throw new IllegalArgumentException("No converter found for type " + itemType);
395-
}
396-
return (C) newCollectionConverter(converter, collectionFactory).convert(value);
383+
final Converter<T> converter,
384+
final Class<C> collectionType) {
385+
Converter<Collection<T>> collectionConverter = newCollectionConverter(converter,
386+
createCollectionFactory(collectionType));
387+
return (Optional<C>) newOptionalConverter(collectionConverter).convert(value);
397388
}
398389

399390
public static <T> T requireValue(final T value, final String name) {

implementation/src/main/java/io/smallrye/config/ConfigMappingGenerator.java

Lines changed: 98 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474

7575
import org.eclipse.microprofile.config.inject.ConfigProperties;
7676
import org.eclipse.microprofile.config.inject.ConfigProperty;
77+
import org.eclipse.microprofile.config.spi.Converter;
7778
import org.objectweb.asm.AnnotationVisitor;
7879
import org.objectweb.asm.ClassVisitor;
7980
import org.objectweb.asm.ClassWriter;
@@ -234,6 +235,7 @@ static byte[] generate(final ConfigMappingInterface mapping) {
234235
private static final String I_OPTIONAL_INT = getInternalName(OptionalInt.class);
235236
private static final String I_OPTIONAL_LONG = getInternalName(OptionalLong.class);
236237
private static final String I_OPTIONAL_DOUBLE = getInternalName(OptionalDouble.class);
238+
private static final String I_CONVERTER = getInternalName(Converter.class);
237239

238240
static byte[] generateBuilder(final ConfigMappingInterface mapping, final String builderClassName) {
239241
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
@@ -251,6 +253,7 @@ static byte[] generateBuilder(final ConfigMappingInterface mapping, final String
251253
continue;
252254
}
253255

256+
// Set Default / Generate method to retrieve the default
254257
String fieldDesc = getDescriptor(property.getMethod().getReturnType());
255258
String memberName = property.getMethod().getName();
256259
String defaultMethodName = "default_" + memberName;
@@ -261,18 +264,27 @@ static byte[] generateBuilder(final ConfigMappingInterface mapping, final String
261264
noArgsCtor.visitMethodInsn(INVOKESTATIC, builderClassName, defaultMethodName, "()" + fieldDesc, false);
262265
noArgsCtor.visitFieldInsn(PUTFIELD, builderClassName, memberName, fieldDesc);
263266
// Default Method
264-
PrimitiveProperty primitive = property.asPrimitive();
267+
PrimitiveProperty primitiveProperty = property.asPrimitive();
265268
MethodVisitor mv = visitor.visitMethod(ACC_PUBLIC | ACC_STATIC, defaultMethodName, "()" + fieldDesc, null,
266269
null);
267270
mv.visitLdcInsn(property.getDefaultValue());
268-
mv.visitLdcInsn(Type.getType(getDescriptor(primitive.getBoxType())));
271+
if (primitiveProperty.hasConvertWith()) {
272+
String convertWith = getInternalName(primitiveProperty.getConvertWith());
273+
mv.visitTypeInsn(NEW, convertWith);
274+
mv.visitInsn(DUP);
275+
mv.visitMethodInsn(INVOKESPECIAL, convertWith, "<init>", "()V", false);
276+
} else {
277+
mv.visitLdcInsn(Type.getType(getDescriptor(primitiveProperty.getBoxType())));
278+
mv.visitMethodInsn(INVOKESTATIC, I_CONFIG_INSTANCE_BUILDER_IMPL, "getConverter",
279+
"(L" + I_CLASS + ";)L" + I_CONVERTER + ";", false);
280+
}
269281
mv.visitMethodInsn(INVOKESTATIC, I_CONFIG_INSTANCE_BUILDER_IMPL, "convertValue",
270-
"(L" + I_STRING + ";L" + I_CLASS + ";)L" + I_OBJECT + ";", false);
271-
mv.visitTypeInsn(CHECKCAST, getInternalName(primitive.getBoxType()));
282+
"(L" + I_STRING + ";L" + I_CONVERTER + ";)L" + I_OBJECT + ";", false);
283+
mv.visitTypeInsn(CHECKCAST, getInternalName(primitiveProperty.getBoxType()));
272284
mv.visitMethodInsn(INVOKEVIRTUAL,
273-
getInternalName(primitive.getBoxType()),
274-
primitive.getUnboxMethodName(),
275-
primitive.getUnboxMethodDescriptor(), false);
285+
getInternalName(primitiveProperty.getBoxType()),
286+
primitiveProperty.getUnboxMethodName(),
287+
primitiveProperty.getUnboxMethodDescriptor(), false);
276288
mv.visitInsn(getReturnInstruction(property));
277289
mv.visitMaxs(0, 0);
278290
mv.visitEnd();
@@ -284,9 +296,18 @@ static byte[] generateBuilder(final ConfigMappingInterface mapping, final String
284296
MethodVisitor mv = visitor.visitMethod(ACC_PUBLIC | ACC_STATIC, defaultMethodName, "()" + fieldDesc, null,
285297
null);
286298
mv.visitLdcInsn(property.getDefaultValue());
287-
mv.visitLdcInsn(Type.getType(fieldDesc));
299+
if (leafProperty.hasConvertWith()) {
300+
String convertWith = getInternalName(leafProperty.getConvertWith());
301+
mv.visitTypeInsn(NEW, convertWith);
302+
mv.visitInsn(DUP);
303+
mv.visitMethodInsn(INVOKESPECIAL, convertWith, "<init>", "()V", false);
304+
} else {
305+
mv.visitLdcInsn(Type.getType(fieldDesc));
306+
mv.visitMethodInsn(INVOKESTATIC, I_CONFIG_INSTANCE_BUILDER_IMPL, "getConverter",
307+
"(L" + I_CLASS + ";)L" + I_CONVERTER + ";", false);
308+
}
288309
mv.visitMethodInsn(INVOKESTATIC, I_CONFIG_INSTANCE_BUILDER_IMPL, "convertValue",
289-
"(L" + I_STRING + ";L" + I_CLASS + ";)L" + I_OBJECT + ";", false);
310+
"(L" + I_STRING + ";L" + I_CONVERTER + ";)L" + I_OBJECT + ";", false);
290311
mv.visitTypeInsn(CHECKCAST, getInternalName(property.getMethod().getReturnType()));
291312
mv.visitInsn(getReturnInstruction(property));
292313
mv.visitMaxs(0, 0);
@@ -317,9 +338,18 @@ static byte[] generateBuilder(final ConfigMappingInterface mapping, final String
317338
null);
318339
LeafProperty optionalProperty = property.asLeaf();
319340
mv.visitLdcInsn(property.getDefaultValue());
320-
mv.visitLdcInsn(Type.getType(getDescriptor(optionalProperty.getValueRawType())));
341+
if (optionalProperty.hasConvertWith()) {
342+
String convertWith = getInternalName(optionalProperty.getConvertWith());
343+
mv.visitTypeInsn(NEW, convertWith);
344+
mv.visitInsn(DUP);
345+
mv.visitMethodInsn(INVOKESPECIAL, convertWith, "<init>", "()V", false);
346+
} else {
347+
mv.visitLdcInsn(Type.getType(getDescriptor(optionalProperty.getValueRawType())));
348+
mv.visitMethodInsn(INVOKESTATIC, I_CONFIG_INSTANCE_BUILDER_IMPL, "getConverter",
349+
"(L" + I_CLASS + ";)L" + I_CONVERTER + ";", false);
350+
}
321351
mv.visitMethodInsn(INVOKESTATIC, I_CONFIG_INSTANCE_BUILDER_IMPL, "convertOptionalValue",
322-
"(L" + I_STRING + ";L" + I_CLASS + ";)L" + I_OPTIONAL + ";", false);
352+
"(L" + I_STRING + ";L" + I_CONVERTER + ";)L" + I_OPTIONAL + ";", false);
323353
mv.visitTypeInsn(CHECKCAST, getInternalName(property.getMethod().getReturnType()));
324354
mv.visitInsn(getReturnInstruction(property));
325355
mv.visitMaxs(0, 0);
@@ -343,7 +373,18 @@ static byte[] generateBuilder(final ConfigMappingInterface mapping, final String
343373
mv.visitTypeInsn(NEW, I_CONFIG_INSTANCE_BUILDER_IMPL + "$MapWithDefault");
344374
mv.visitInsn(DUP);
345375
mv.visitLdcInsn(mapProperty.getDefaultValue());
346-
// TODO - Miss Converter
376+
if (valueProperty.hasConvertWith()) {
377+
String convertWith = getInternalName(valueProperty.asLeaf().getConvertWith());
378+
mv.visitTypeInsn(NEW, convertWith);
379+
mv.visitInsn(DUP);
380+
mv.visitMethodInsn(INVOKESPECIAL, convertWith, "<init>", "()V", false);
381+
} else {
382+
mv.visitLdcInsn(getType(valueProperty.asLeaf().getValueRawType()));
383+
mv.visitMethodInsn(INVOKESTATIC, I_CONFIG_INSTANCE_BUILDER_IMPL, "getConverter",
384+
"(L" + I_CLASS + ";)L" + I_CONVERTER + ";", false);
385+
}
386+
mv.visitMethodInsn(INVOKESTATIC, I_CONFIG_INSTANCE_BUILDER_IMPL, "convertValue",
387+
"(L" + I_STRING + ";L" + I_CONVERTER + ";)L" + I_OBJECT + ";", false);
347388
mv.visitMethodInsn(INVOKESPECIAL, I_CONFIG_INSTANCE_BUILDER_IMPL + "$MapWithDefault", "<init>",
348389
"(L" + I_OBJECT + ";)V", false);
349390
mv.visitInsn(getReturnInstruction(property));
@@ -367,10 +408,19 @@ static byte[] generateBuilder(final ConfigMappingInterface mapping, final String
367408
mv.visitTypeInsn(NEW, I_CONFIG_INSTANCE_BUILDER_IMPL + "$MapWithDefault");
368409
mv.visitInsn(DUP);
369410
mv.visitLdcInsn(mapProperty.getDefaultValue());
370-
mv.visitLdcInsn(Type.getType(getDescriptor(elementProperty.getValueRawType())));
411+
if (elementProperty.hasConvertWith()) {
412+
String convertWith = getInternalName(elementProperty.getConvertWith());
413+
mv.visitTypeInsn(NEW, convertWith);
414+
mv.visitInsn(DUP);
415+
mv.visitMethodInsn(INVOKESPECIAL, convertWith, "<init>", "()V", false);
416+
} else {
417+
mv.visitLdcInsn(getType(elementProperty.getValueRawType()));
418+
mv.visitMethodInsn(INVOKESTATIC, I_CONFIG_INSTANCE_BUILDER_IMPL, "getConverter",
419+
"(L" + I_CLASS + ";)L" + I_CONVERTER + ";", false);
420+
}
371421
mv.visitLdcInsn(Type.getType(getDescriptor(collectionProperty.getCollectionRawType())));
372422
mv.visitMethodInsn(INVOKESTATIC, I_CONFIG_INSTANCE_BUILDER_IMPL, "convertValues",
373-
"(L" + I_STRING + ";L" + I_CLASS + ";L" + I_CLASS + ";)L" + I_COLLECTION + ";", false);
423+
"(L" + I_STRING + ";L" + I_CONVERTER + ";L" + I_CLASS + ";)L" + I_COLLECTION + ";", false);
374424
mv.visitMethodInsn(INVOKESPECIAL, I_CONFIG_INSTANCE_BUILDER_IMPL + "$MapWithDefault", "<init>",
375425
"(L" + I_OBJECT + ";)V", false);
376426
mv.visitInsn(getReturnInstruction(property));
@@ -418,10 +468,19 @@ static byte[] generateBuilder(final ConfigMappingInterface mapping, final String
418468
MethodVisitor mv = visitor.visitMethod(ACC_PUBLIC | ACC_STATIC, defaultMethodName, "()" + fieldDesc, null,
419469
null);
420470
mv.visitLdcInsn(elementProperty.getDefaultValue());
421-
mv.visitLdcInsn(Type.getType(getDescriptor(elementProperty.getValueRawType())));
471+
if (elementProperty.hasConvertWith()) {
472+
String convertWith = getInternalName(elementProperty.getConvertWith());
473+
mv.visitTypeInsn(NEW, convertWith);
474+
mv.visitInsn(DUP);
475+
mv.visitMethodInsn(INVOKESPECIAL, convertWith, "<init>", "()V", false);
476+
} else {
477+
mv.visitLdcInsn(Type.getType(getDescriptor(elementProperty.getValueRawType())));
478+
mv.visitMethodInsn(INVOKESTATIC, I_CONFIG_INSTANCE_BUILDER_IMPL, "getConverter",
479+
"(L" + I_CLASS + ";)L" + I_CONVERTER + ";", false);
480+
}
422481
mv.visitLdcInsn(Type.getType(getDescriptor(collectionProperty.getCollectionRawType())));
423482
mv.visitMethodInsn(INVOKESTATIC, I_CONFIG_INSTANCE_BUILDER_IMPL, "convertValues",
424-
"(L" + I_STRING + ";L" + I_CLASS + ";L" + I_CLASS + ";)L" + I_COLLECTION + ";", false);
483+
"(L" + I_STRING + ";L" + I_CONVERTER + ";L" + I_CLASS + ";)L" + I_COLLECTION + ";", false);
425484
mv.visitTypeInsn(CHECKCAST, getInternalName(property.getMethod().getReturnType()));
426485
mv.visitInsn(getReturnInstruction(property));
427486
mv.visitMaxs(0, 0);
@@ -432,7 +491,28 @@ static byte[] generateBuilder(final ConfigMappingInterface mapping, final String
432491
CollectionProperty collectionProperty = property.asOptional().getNestedProperty().asCollection();
433492
LeafProperty elementProperty = collectionProperty.getElement().asLeaf();
434493
if (elementProperty.hasDefaultValue() && elementProperty.getDefaultValue() != null) {
435-
throw new UnsupportedOperationException();
494+
generateGetterWithDefaullt = true;
495+
// Default Method
496+
MethodVisitor mv = visitor.visitMethod(ACC_PUBLIC | ACC_STATIC, defaultMethodName, "()" + fieldDesc, null,
497+
null);
498+
mv.visitLdcInsn(elementProperty.getDefaultValue());
499+
if (elementProperty.hasConvertWith()) {
500+
String convertWith = getInternalName(elementProperty.getConvertWith());
501+
mv.visitTypeInsn(NEW, convertWith);
502+
mv.visitInsn(DUP);
503+
mv.visitMethodInsn(INVOKESPECIAL, convertWith, "<init>", "()V", false);
504+
} else {
505+
mv.visitLdcInsn(Type.getType(getDescriptor(elementProperty.getValueRawType())));
506+
mv.visitMethodInsn(INVOKESTATIC, I_CONFIG_INSTANCE_BUILDER_IMPL, "getConverter",
507+
"(L" + I_CLASS + ";)L" + I_CONVERTER + ";", false);
508+
}
509+
mv.visitLdcInsn(Type.getType(getDescriptor(collectionProperty.getCollectionRawType())));
510+
mv.visitMethodInsn(INVOKESTATIC, I_CONFIG_INSTANCE_BUILDER_IMPL, "convertOptionalValues",
511+
"(L" + I_STRING + ";L" + I_CONVERTER + ";L" + I_CLASS + ";)L" + I_OPTIONAL + ";", false);
512+
mv.visitTypeInsn(CHECKCAST, getInternalName(property.getMethod().getReturnType()));
513+
mv.visitInsn(getReturnInstruction(property));
514+
mv.visitMaxs(0, 0);
515+
mv.visitEnd();
436516
} else {
437517
// There is no default, but we initialize an empty Optional inline in field
438518
noArgsCtor.visitVarInsn(ALOAD, V_THIS);
@@ -459,6 +539,7 @@ static byte[] generateBuilder(final ConfigMappingInterface mapping, final String
459539
noArgsCtor.visitFieldInsn(PUTFIELD, builderClassName, memberName, "L" + I_OPTIONAL + ";");
460540
}
461541

542+
// Getter
462543
MethodVisitor mv = visitor.visitMethod(ACC_PUBLIC, memberName, "()" + fieldDesc, null, null);
463544
if (generateGetterWithDefaullt) {
464545
mv.visitVarInsn(ALOAD, V_THIS);
@@ -493,7 +574,6 @@ static byte[] generateBuilder(final ConfigMappingInterface mapping, final String
493574

494575
// Field Declaration
495576
String fieldDesc = getDescriptor(method.getReturnType());
496-
// TODO - Should it be public? And use field access to copy from the builder to the config class?
497577
visitor.visitField(ACC_PUBLIC, memberName, fieldDesc, null, null);
498578

499579
// Setter

0 commit comments

Comments
 (0)