mirror of
https://github.com/jlengrand/helidon.git
synced 2026-03-10 08:21:17 +00:00
Fixes for MP quickstart in native image. (#1564)
* Fixes for MP quickstart in native image. * Mp Quicstart update - fix injection and documentation. Signed-off-by: Tomas Langer <tomas.langer@oracle.com>
This commit is contained in:
@@ -18,7 +18,6 @@ package io.helidon.config;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -455,12 +454,7 @@ class BuilderImpl implements Config.Builder {
|
||||
hasEnvVarSource = true;
|
||||
hasSystemPropertiesSource = true;
|
||||
|
||||
prioritizedSources.add(new HelidonSourceWithPriority(ConfigSources.systemProperties()
|
||||
.pollingStrategy(PollingStrategies
|
||||
.regular(Duration.ofSeconds(2))
|
||||
.build())
|
||||
.build(),
|
||||
100));
|
||||
prioritizedSources.add(new HelidonSourceWithPriority(ConfigSources.systemProperties().build(), 100));
|
||||
prioritizedSources.add(new HelidonSourceWithPriority(ConfigSources.environmentVariables(), 100));
|
||||
prioritizedSources.add(new HelidonSourceWithPriority(ConfigSources.classpath("application.yaml")
|
||||
.optional(true)
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Oracle and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.helidon.config.objectmapping;
|
||||
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A replacement for {@link java.lang.invoke.MethodHandle} that we cannot use for the time being, due to
|
||||
* limitations of GraalVM native image.
|
||||
*/
|
||||
interface HelidonMethodHandle {
|
||||
static HelidonMethodHandle create(Class<?> type, Constructor<?> constructor) {
|
||||
return new ReflectionUtil.ConstructorMethodHandle(type, constructor);
|
||||
}
|
||||
|
||||
static HelidonMethodHandle create(Class<?> type, Method method) {
|
||||
if (Modifier.isStatic(method.getModifiers())) {
|
||||
return new ReflectionUtil.StaticMethodHandle(method);
|
||||
} else {
|
||||
return new ReflectionUtil.InstanceMethodHandle(type, method);
|
||||
}
|
||||
}
|
||||
|
||||
static HelidonMethodHandle create(Class<?> type, Field field) {
|
||||
return new ReflectionUtil.FieldMethodHandle(type, field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the method or constructor with params.
|
||||
* @param params parameters
|
||||
* @return response
|
||||
*/
|
||||
Object invoke(List<Object> params);
|
||||
|
||||
/**
|
||||
* Type of this handle, see {@link java.lang.invoke.MethodHandle#type()}.
|
||||
*
|
||||
* @return type of this handle
|
||||
*/
|
||||
MethodType type();
|
||||
|
||||
/**
|
||||
* Invoke with varargs, delegates to {@link #invoke(java.util.List)}.
|
||||
*
|
||||
* @param params parameters
|
||||
* @return result of the operation, or null (for setters)
|
||||
*/
|
||||
default Object invoke(Object... params) {
|
||||
return invoke(Arrays.asList(params));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2020 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2020 Oracle and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,13 +15,13 @@
|
||||
*/
|
||||
package io.helidon.config.objectmapping;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.annotation.Priority;
|
||||
|
||||
import io.helidon.common.HelidonFeatures;
|
||||
import io.helidon.config.Config;
|
||||
import io.helidon.config.objectmapping.ObjectConfigMappers.BuilderConfigMapper;
|
||||
import io.helidon.config.objectmapping.ObjectConfigMappers.ConfigMethodHandleConfigMapper;
|
||||
@@ -50,6 +50,10 @@ public class ObjectConfigMapperProvider implements ConfigMapperProvider {
|
||||
private static final String METHOD_PARSE = "parse";
|
||||
private static final String METHOD_CREATE = "create";
|
||||
|
||||
static {
|
||||
HelidonFeatures.register("Config", "Object Mapping");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Class<?>, Function<Config, ?>> mappers() {
|
||||
return Map.of();
|
||||
@@ -110,7 +114,7 @@ public class ObjectConfigMapperProvider implements ConfigMapperProvider {
|
||||
private static <T> Optional<Function<Config, T>> findStaticStringMethodMapper(Class<T> type,
|
||||
String methodName) {
|
||||
|
||||
Optional<MethodHandle> method = findStaticMethod(type,
|
||||
Optional<HelidonMethodHandle> method = findStaticMethod(type,
|
||||
methodName,
|
||||
String.class);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2020 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2020 Oracle and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,11 +15,10 @@
|
||||
*/
|
||||
package io.helidon.config.objectmapping;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import io.helidon.common.HelidonFeatures;
|
||||
import io.helidon.config.Config;
|
||||
import io.helidon.config.ConfigMappingException;
|
||||
import io.helidon.config.MissingValueException;
|
||||
@@ -31,16 +30,12 @@ import io.helidon.config.objectmapping.ReflectionUtil.PropertyAccessor;
|
||||
*/
|
||||
class ObjectConfigMappers {
|
||||
|
||||
static {
|
||||
HelidonFeatures.register("Config", "Object Mapping");
|
||||
}
|
||||
|
||||
abstract static class MethodHandleConfigMapper<T, P> implements Function<Config, T> {
|
||||
private final Class<T> type;
|
||||
private final String methodName;
|
||||
private final MethodHandle methodHandle;
|
||||
private final HelidonMethodHandle methodHandle;
|
||||
|
||||
MethodHandleConfigMapper(Class<T> type, String methodName, MethodHandle methodHandle) {
|
||||
MethodHandleConfigMapper(Class<T> type, String methodName, HelidonMethodHandle methodHandle) {
|
||||
this.type = type;
|
||||
this.methodName = methodName;
|
||||
this.methodHandle = methodHandle;
|
||||
@@ -51,7 +46,7 @@ class ObjectConfigMappers {
|
||||
@Override
|
||||
public T apply(Config config) throws ConfigMappingException, MissingValueException {
|
||||
try {
|
||||
return type.cast(methodHandle.invoke(invokeParameter(config)));
|
||||
return type.cast(methodHandle.invoke(List.of(invokeParameter(config))));
|
||||
} catch (ConfigMappingException ex) {
|
||||
throw ex;
|
||||
} catch (Throwable ex) {
|
||||
@@ -62,7 +57,7 @@ class ObjectConfigMappers {
|
||||
}
|
||||
|
||||
static class ConfigMethodHandleConfigMapper<T> extends MethodHandleConfigMapper<T, Config> {
|
||||
ConfigMethodHandleConfigMapper(Class<T> type, String methodName, MethodHandle methodHandle) {
|
||||
ConfigMethodHandleConfigMapper(Class<T> type, String methodName, HelidonMethodHandle methodHandle) {
|
||||
super(type, methodName, methodHandle);
|
||||
}
|
||||
|
||||
@@ -73,7 +68,7 @@ class ObjectConfigMappers {
|
||||
}
|
||||
|
||||
static class StringMethodHandleConfigMapper<T> extends MethodHandleConfigMapper<T, String> {
|
||||
StringMethodHandleConfigMapper(Class<T> type, String methodName, MethodHandle methodHandle) {
|
||||
StringMethodHandleConfigMapper(Class<T> type, String methodName, HelidonMethodHandle methodHandle) {
|
||||
super(type, methodName, methodHandle);
|
||||
}
|
||||
|
||||
@@ -176,10 +171,10 @@ class ObjectConfigMappers {
|
||||
static class GenericConfigMapper<T> implements Function<Config, T> {
|
||||
|
||||
private final Class<T> type;
|
||||
private final MethodHandle constructorHandle;
|
||||
private final HelidonMethodHandle constructorHandle;
|
||||
private final Collection<PropertyAccessor<?>> propertyAccessors;
|
||||
|
||||
GenericConfigMapper(Class<T> type, MethodHandle constructorHandle) {
|
||||
GenericConfigMapper(Class<T> type, HelidonMethodHandle constructorHandle) {
|
||||
this.type = type;
|
||||
this.constructorHandle = constructorHandle;
|
||||
|
||||
@@ -192,7 +187,7 @@ class ObjectConfigMappers {
|
||||
@Override
|
||||
public T apply(Config config) throws ConfigMappingException, MissingValueException {
|
||||
try {
|
||||
T instance = type.cast(constructorHandle.invoke());
|
||||
T instance = type.cast(constructorHandle.invoke(List.of()));
|
||||
|
||||
for (PropertyAccessor<?> propertyAccessor : propertyAccessors) {
|
||||
propertyAccessor.set(instance, config.get(propertyAccessor.name()));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2020 Oracle and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package io.helidon.config.objectmapping;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Constructor;
|
||||
@@ -76,11 +74,11 @@ final class ReflectionUtil {
|
||||
return (Class<T>) REPLACED_TYPES.getOrDefault(type, type);
|
||||
}
|
||||
|
||||
static Optional<MethodHandle> findStaticMethod(Class<?> type, String methodName, Class<?>... parameterTypes) {
|
||||
static Optional<HelidonMethodHandle> findStaticMethod(Class<?> type, String methodName, Class<?>... parameterTypes) {
|
||||
try {
|
||||
Method method = type.getMethod(methodName, parameterTypes);
|
||||
if (checkMethod(method, true, type, methodName, parameterTypes.length > 0)) {
|
||||
return unreflect(method);
|
||||
return Optional.of(HelidonMethodHandle.create(type, method));
|
||||
} else {
|
||||
LOGGER.log(Level.FINEST,
|
||||
() -> "Class " + type.getName() + " method '" + methodName
|
||||
@@ -95,11 +93,11 @@ final class ReflectionUtil {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
static Optional<MethodHandle> findConstructor(Class<?> type, Class<?>... parameterTypes) {
|
||||
static Optional<HelidonMethodHandle> findConstructor(Class<?> type, Class<?>... parameterTypes) {
|
||||
try {
|
||||
Constructor<?> constructor = type.getConstructor(parameterTypes);
|
||||
if (checkConstructor(constructor, parameterTypes.length > 0)) {
|
||||
return Optional.of(MethodHandles.publicLookup().unreflectConstructor(constructor));
|
||||
return Optional.of(HelidonMethodHandle.create(type, constructor));
|
||||
} else {
|
||||
LOGGER.log(Level.FINEST,
|
||||
() -> "Class " + type.getName() + " constructor with parameters "
|
||||
@@ -111,11 +109,6 @@ final class ReflectionUtil {
|
||||
ex,
|
||||
() -> "Class " + type.getName() + " does not have a constructor with parameters "
|
||||
+ Arrays.toString(parameterTypes) + ".");
|
||||
} catch (IllegalAccessException ex) {
|
||||
LOGGER.log(Level.FINER,
|
||||
ex,
|
||||
() -> "Access checking fails on " + type.getName()
|
||||
+ " class, constructor with parameters " + Arrays.toString(parameterTypes) + ".");
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
@@ -125,14 +118,16 @@ final class ReflectionUtil {
|
||||
* e.g. Type t = Type.builder().build();
|
||||
*/
|
||||
static <T> Optional<BuilderAccessor<T>> findBuilderMethod(Class<T> type) {
|
||||
return findMethod(type, METHOD_BUILDER, true, null).flatMap(
|
||||
builderMethod -> unreflect(builderMethod).flatMap(
|
||||
builderHandler -> findBuilderBuildHandler(type, builderMethod.getReturnType()).map(
|
||||
buildHandler ->
|
||||
new BuilderAccessor<>(builderMethod.getReturnType(),
|
||||
builderHandler,
|
||||
type,
|
||||
buildHandler))));
|
||||
return findMethod(type, METHOD_BUILDER, true, null)
|
||||
.flatMap(builderMethod -> {
|
||||
HelidonMethodHandle builderHandler = HelidonMethodHandle.create(type, builderMethod);
|
||||
return findBuilderBuildHandler(type, builderMethod.getReturnType()).map(
|
||||
buildHandler ->
|
||||
new BuilderAccessor<>(builderMethod.getReturnType(),
|
||||
builderHandler,
|
||||
type,
|
||||
buildHandler));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,9 +198,9 @@ final class ReflectionUtil {
|
||||
}
|
||||
}
|
||||
|
||||
static <T> Optional<MethodHandle> findBuilderBuildHandler(Class<T> type, Class<?> builderType) {
|
||||
static <T> Optional<HelidonMethodHandle> findBuilderBuildHandler(Class<T> type, Class<?> builderType) {
|
||||
return findMethod(builderType, METHOD_BUILD, false, type)
|
||||
.flatMap(ReflectionUtil::unreflect);
|
||||
.map(it -> HelidonMethodHandle.create(type, it));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -249,18 +244,6 @@ final class ReflectionUtil {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private static Optional<MethodHandle> unreflect(Method method) {
|
||||
try {
|
||||
return Optional.of(MethodHandles.publicLookup().unreflect(method));
|
||||
} catch (IllegalAccessException ex) {
|
||||
LOGGER.log(Level.FINER,
|
||||
ex,
|
||||
() -> "Access checking fails on " + method.getDeclaringClass() + " class, method '" + method.getName()
|
||||
+ "' with parameters " + Arrays.asList(method.getParameters()) + ".");
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* The class covers work with factory method.
|
||||
*
|
||||
@@ -268,11 +251,11 @@ final class ReflectionUtil {
|
||||
*/
|
||||
static class FactoryAccessor<T> {
|
||||
private final Class<T> type;
|
||||
private final MethodHandle handle;
|
||||
private final HelidonMethodHandle handle;
|
||||
private final LinkedHashMap<String, PropertyWrapper<?>> parameterValueProviders;
|
||||
|
||||
FactoryAccessor(Class<T> type,
|
||||
MethodHandle handle,
|
||||
HelidonMethodHandle handle,
|
||||
Parameter[] parameters) {
|
||||
this.type = type;
|
||||
this.handle = handle;
|
||||
@@ -284,7 +267,7 @@ final class ReflectionUtil {
|
||||
List<Object> args = createArguments(configNode);
|
||||
|
||||
try {
|
||||
Object obj = handle.invokeWithArguments(args);
|
||||
Object obj = handle.invoke(args);
|
||||
return type.cast(obj);
|
||||
} catch (ConfigException ex) {
|
||||
throw ex;
|
||||
@@ -350,15 +333,15 @@ final class ReflectionUtil {
|
||||
*/
|
||||
static class BuilderAccessor<T> {
|
||||
private final Class<?> builderType;
|
||||
private final MethodHandle builderHandler;
|
||||
private final HelidonMethodHandle builderHandler;
|
||||
private final Class<T> buildType;
|
||||
private final MethodHandle buildHandler;
|
||||
private final HelidonMethodHandle buildHandler;
|
||||
private final Collection<PropertyAccessor<?>> builderAccessors;
|
||||
|
||||
BuilderAccessor(Class<?> builderType,
|
||||
MethodHandle builderHandler,
|
||||
HelidonMethodHandle builderHandler,
|
||||
Class<T> buildType,
|
||||
MethodHandle buildHandler) {
|
||||
HelidonMethodHandle buildHandler) {
|
||||
this.builderType = builderType;
|
||||
this.builderHandler = builderHandler;
|
||||
this.buildType = buildType;
|
||||
@@ -369,13 +352,13 @@ final class ReflectionUtil {
|
||||
|
||||
public T create(Config config) {
|
||||
try {
|
||||
Object builder = builderType.cast(builderHandler.invoke());
|
||||
Object builder = builderType.cast(builderHandler.invoke(List.of()));
|
||||
|
||||
for (PropertyAccessor<?> builderAccessor : builderAccessors) {
|
||||
builderAccessor.set(builder, config.get(builderAccessor.name()));
|
||||
}
|
||||
|
||||
return buildType.cast(buildHandler.invoke(builder));
|
||||
return buildType.cast(buildHandler.invoke(List.of(builder)));
|
||||
} catch (ConfigMappingException ex) {
|
||||
throw ex;
|
||||
} catch (Throwable ex) {
|
||||
@@ -393,14 +376,14 @@ final class ReflectionUtil {
|
||||
*/
|
||||
static class PropertyAccessor<T> {
|
||||
private final String name;
|
||||
private final MethodHandle handle;
|
||||
private final HelidonMethodHandle handle;
|
||||
private final boolean hasValueAnnotation;
|
||||
private final PropertyWrapper<T> propertyWrapper;
|
||||
|
||||
PropertyAccessor(String name, Class<T> propertyType,
|
||||
Class<?> configAsType,
|
||||
boolean list,
|
||||
MethodHandle handle,
|
||||
HelidonMethodHandle handle,
|
||||
Value value) {
|
||||
this.name = name;
|
||||
this.handle = handle;
|
||||
@@ -432,7 +415,7 @@ final class ReflectionUtil {
|
||||
}
|
||||
}
|
||||
|
||||
MethodHandle handle() {
|
||||
HelidonMethodHandle handle() {
|
||||
return handle;
|
||||
}
|
||||
|
||||
@@ -555,30 +538,26 @@ final class ReflectionUtil {
|
||||
static <T> PropertyAccessor<T> createPropertyAccessor(Class<T> type,
|
||||
String name,
|
||||
Method method) {
|
||||
try {
|
||||
final Class<T> propertyType = (Class<T>) method.getParameterTypes()[0];
|
||||
Class<?> configAsType = propertyType;
|
||||
final Class<T> propertyType = (Class<T>) method.getParameterTypes()[0];
|
||||
Class<?> configAsType = propertyType;
|
||||
|
||||
boolean list = List.class.isAssignableFrom(configAsType);
|
||||
if (list) {
|
||||
Type genType = method.getGenericParameterTypes()[0];
|
||||
if (genType instanceof ParameterizedType) {
|
||||
configAsType = (Class<?>) ((ParameterizedType) genType).getActualTypeArguments()[0];
|
||||
} else {
|
||||
throw new ConfigException("Unable to find generic type of List on setter parameter: " + method);
|
||||
}
|
||||
boolean list = List.class.isAssignableFrom(configAsType);
|
||||
if (list) {
|
||||
Type genType = method.getGenericParameterTypes()[0];
|
||||
if (genType instanceof ParameterizedType) {
|
||||
configAsType = (Class<?>) ((ParameterizedType) genType).getActualTypeArguments()[0];
|
||||
} else {
|
||||
throw new ConfigException("Unable to find generic type of List on setter parameter: " + method);
|
||||
}
|
||||
|
||||
MethodHandle handle = MethodHandles.publicLookup()
|
||||
.findVirtual(type,
|
||||
method.getName(),
|
||||
MethodType.methodType(method.getReturnType(), method.getParameterTypes()));
|
||||
|
||||
return new PropertyAccessor<>(name, propertyType, configAsType, list, handle,
|
||||
method.getAnnotation(Value.class));
|
||||
} catch (NoSuchMethodException | IllegalAccessException | ClassCastException ex) {
|
||||
throw new ConfigException("Cannot access setter: " + method, ex);
|
||||
}
|
||||
|
||||
return new PropertyAccessor<>(name,
|
||||
propertyType,
|
||||
configAsType,
|
||||
list,
|
||||
HelidonMethodHandle.create(type, method),
|
||||
method.getAnnotation(Value.class));
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -599,12 +578,13 @@ final class ReflectionUtil {
|
||||
}
|
||||
}
|
||||
|
||||
MethodHandle handle = MethodHandles.publicLookup()
|
||||
.findSetter(type, field.getName(), field.getType());
|
||||
|
||||
return new PropertyAccessor<>(name, propertyType, configAsType, list, handle,
|
||||
return new PropertyAccessor<>(name,
|
||||
propertyType,
|
||||
configAsType,
|
||||
list,
|
||||
HelidonMethodHandle.create(type, field),
|
||||
field.getAnnotation(Value.class));
|
||||
} catch (NoSuchFieldException | IllegalAccessException | ClassCastException ex) {
|
||||
} catch (ClassCastException ex) {
|
||||
throw new ConfigException("Cannot access field: " + field, ex);
|
||||
}
|
||||
}
|
||||
@@ -728,4 +708,116 @@ final class ReflectionUtil {
|
||||
this.defaultSupplier = defaultSupplier;
|
||||
}
|
||||
}
|
||||
|
||||
static class FieldMethodHandle implements HelidonMethodHandle {
|
||||
private final Field field;
|
||||
private final Class<?> type;
|
||||
|
||||
FieldMethodHandle(Class<?> type, Field field) {
|
||||
this.type = type;
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(List<Object> params) {
|
||||
try {
|
||||
field.set(params.get(0), params.get(1));
|
||||
return null;
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new ConfigException("Field " + field + " is not accessible. Cannot set value", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodType type() {
|
||||
return MethodType.methodType(Void.class, type, field.getType());
|
||||
}
|
||||
}
|
||||
|
||||
static class StaticMethodHandle implements HelidonMethodHandle {
|
||||
private final Method method;
|
||||
|
||||
StaticMethodHandle(Method method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(List<Object> params) {
|
||||
try {
|
||||
return method.invoke(null, params.toArray(new Object[0]));
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new ConfigException("Method " + method + " is not accessible. Cannot invoke", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new ConfigException("Failed to invoke method " + method, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodType type() {
|
||||
return MethodType.methodType(method.getReturnType(), method.getParameterTypes());
|
||||
}
|
||||
}
|
||||
|
||||
static class ConstructorMethodHandle implements HelidonMethodHandle {
|
||||
private final Class<?> type;
|
||||
private final Constructor<?> constructor;
|
||||
|
||||
ConstructorMethodHandle(Class<?> type, Constructor<?> constructor) {
|
||||
this.type = type;
|
||||
this.constructor = constructor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(List<Object> params) {
|
||||
try {
|
||||
return constructor.newInstance(params.toArray(new Object[0]));
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new ConfigException("Constructor " + constructor + " is not accessible. Cannot invoke", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new ConfigException("Failed to invoke constructor " + constructor, e);
|
||||
} catch (InstantiationException e) {
|
||||
throw new ConfigException("Failed to instantiate class using constructor " + constructor, e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ConfigException("Parameters mismatch for constructor " + constructor, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodType type() {
|
||||
return MethodType.methodType(type);
|
||||
}
|
||||
}
|
||||
|
||||
public static class InstanceMethodHandle implements HelidonMethodHandle {
|
||||
private Class<?> type;
|
||||
private final Method method;
|
||||
|
||||
InstanceMethodHandle(Class<?> type, Method method) {
|
||||
this.type = type;
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(List<Object> params) {
|
||||
try {
|
||||
// first is instance
|
||||
Object instance = params.get(0);
|
||||
List<Object> mutableParams = new ArrayList<>(params);
|
||||
mutableParams.remove(0);
|
||||
return method.invoke(params.get(0), mutableParams.toArray(new Object[0]));
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new ConfigException("Method " + method + " is not accessible. Cannot invoke", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new ConfigException("Failed to invoke method " + method, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodType type() {
|
||||
List<Class<?>> paramTypes = new ArrayList<>();
|
||||
paramTypes.add(type);
|
||||
paramTypes.addAll(Arrays.asList(method.getParameterTypes()));
|
||||
return MethodType.methodType(method.getReturnType(), paramTypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2018, 2020 Oracle and/or its affiliates. All rights reserved.
|
||||
Copyright (c) 2018, 2020 Oracle and/or its affiliates.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -31,19 +31,11 @@
|
||||
<artifactId>helidon-quickstart-mp</artifactId>
|
||||
<name>Helidon Quickstart MP Example</name>
|
||||
|
||||
<properties>
|
||||
<mainClass>io.helidon.examples.quickstart.mp.Main</mainClass>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.helidon.microprofile.bundles</groupId>
|
||||
<artifactId>helidon-microprofile</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.media</groupId>
|
||||
<artifactId>jersey-media-json-binding</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss</groupId>
|
||||
<artifactId>jandex</artifactId>
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2020 Oracle and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.helidon.examples.quickstart.mp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.logging.LogManager;
|
||||
|
||||
import io.helidon.microprofile.server.Server;
|
||||
|
||||
/**
|
||||
* The application main class.
|
||||
*/
|
||||
public final class Main {
|
||||
|
||||
/**
|
||||
* Cannot be instantiated.
|
||||
*/
|
||||
private Main() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Application main entry point.
|
||||
* @param args command line arguments
|
||||
* @throws IOException if there are problems reading logging properties
|
||||
*/
|
||||
public static void main(final String[] args) throws IOException {
|
||||
// load logging configuration
|
||||
setupLogging();
|
||||
|
||||
// start the server
|
||||
Server server = startServer();
|
||||
|
||||
System.out.println("http://localhost:" + server.port() + "/greet");
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the server.
|
||||
* @return the created {@link Server} instance
|
||||
*/
|
||||
static Server startServer() {
|
||||
// Server will automatically pick up configuration from
|
||||
// microprofile-config.properties
|
||||
// and Application classes annotated as @ApplicationScoped
|
||||
return Server.create().start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure logging from logging.properties file.
|
||||
*/
|
||||
private static void setupLogging() throws IOException {
|
||||
try (InputStream is = Main.class.getResourceAsStream("/logging.properties")) {
|
||||
LogManager.getLogManager().readConfiguration(is);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2020 Oracle and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,21 +19,24 @@ import javax.enterprise.context.ApplicationScoped;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import io.helidon.microprofile.server.RoutingPath;
|
||||
import io.helidon.security.SecurityContext;
|
||||
import io.helidon.security.Security;
|
||||
import io.helidon.webserver.Routing;
|
||||
import io.helidon.webserver.Service;
|
||||
|
||||
/**
|
||||
* TODO javadoc.
|
||||
* Reactive service.
|
||||
* <p>
|
||||
* Helidon WebServer reactive services can be used in MP as well.
|
||||
* Injection is limited to {@link javax.enterprise.context.ApplicationScoped}.
|
||||
*/
|
||||
@ApplicationScoped
|
||||
@RoutingPath("/reactive")
|
||||
public class ReactiveService implements Service {
|
||||
@Inject
|
||||
private SecurityContext securityContext;
|
||||
private Security security;
|
||||
|
||||
@Override
|
||||
public void update(Routing.Rules rules) {
|
||||
rules.get("/", (req, res) -> res.send("Context: " + securityContext));
|
||||
rules.get("/", (req, res) -> res.send("Security: " + security));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2020 Oracle and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -37,7 +37,7 @@ class MainTest {
|
||||
|
||||
@BeforeAll
|
||||
public static void startTheServer() throws Exception {
|
||||
server = Main.startServer();
|
||||
server = Server.create().start();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -102,17 +102,17 @@ Start the application:
|
||||
Build the "jlink" Docker Image
|
||||
|
||||
```
|
||||
docker build -t helidon-quickstart-se-jlink -f Dockerfile.jlink .
|
||||
docker build -t helidon-quickstart-mp-jlink -f Dockerfile.jlink .
|
||||
```
|
||||
|
||||
Start the application:
|
||||
|
||||
```
|
||||
docker run --rm -p 8080:8080 helidon-quickstart-se-jlink:latest
|
||||
docker run --rm -p 8080:8080 helidon-quickstart-mp-jlink:latest
|
||||
```
|
||||
|
||||
See the start script help:
|
||||
|
||||
```
|
||||
docker run --rm helidon-quickstart-se-jlink:latest --help
|
||||
docker run --rm helidon-quickstart-mp-jlink:latest --help
|
||||
```
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2020 Oracle and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,8 @@
|
||||
package io.helidon.health.checks;
|
||||
|
||||
import java.lang.management.ThreadMXBean;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
import javax.inject.Inject;
|
||||
@@ -37,6 +39,8 @@ import org.eclipse.microprofile.health.Liveness;
|
||||
@ApplicationScoped // this will be ignored if not within CDI
|
||||
@BuiltInHealthCheck
|
||||
public final class DeadlockHealthCheck implements HealthCheck {
|
||||
private static final Logger LOGGER = Logger.getLogger(DeadlockHealthCheck.class.getName());
|
||||
|
||||
/**
|
||||
* Used for detecting deadlocks. Injected in the constructor.
|
||||
*/
|
||||
@@ -61,8 +65,14 @@ public final class DeadlockHealthCheck implements HealthCheck {
|
||||
|
||||
@Override
|
||||
public HealthCheckResponse call() {
|
||||
// Thanks to https://stackoverflow.com/questions/1102359/programmatic-deadlock-detection-in-java#1102410
|
||||
boolean noDeadLock = (threadBean.findDeadlockedThreads() == null);
|
||||
boolean noDeadLock = false;
|
||||
try {
|
||||
// Thanks to https://stackoverflow.com/questions/1102359/programmatic-deadlock-detection-in-java#1102410
|
||||
noDeadLock = (threadBean.findDeadlockedThreads() == null);
|
||||
} catch (Throwable e) {
|
||||
// ThreadBean does not work - probably in native image
|
||||
LOGGER.log(Level.FINEST, "Failed to find deadlocks in ThreadMXBean, ignoring this healthcheck", e);
|
||||
}
|
||||
return HealthCheckResponse.named("deadlock")
|
||||
.state(noDeadLock)
|
||||
.build();
|
||||
|
||||
@@ -203,7 +203,7 @@ public final class HealthSupport implements Service {
|
||||
private HcResponse callHealthChecks(HealthCheck hc) {
|
||||
try {
|
||||
return new HcResponse(hc.call());
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
LOGGER.log(Level.SEVERE, "Failed to compute health check for " + hc.getClass().getName(), e);
|
||||
|
||||
return new HcResponse(HealthCheckResponse
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved.
|
||||
Copyright (c) 2019, 2020 Oracle and/or its affiliates.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -78,17 +78,11 @@
|
||||
<groupId>org.glassfish.jersey.media</groupId>
|
||||
<artifactId>jersey-media-json-binding</artifactId>
|
||||
<scope>runtime</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<!-- Jersey depends on an older version -->
|
||||
<groupId>org.eclipse</groupId>
|
||||
<artifactId>yasson</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse</groupId>
|
||||
<artifactId>yasson</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
[
|
||||
{
|
||||
"bean-class": "io.helidon.security.SecurityContext",
|
||||
"ifaces": [
|
||||
"io.helidon.security.SecurityContext"
|
||||
]
|
||||
},
|
||||
{
|
||||
"bean-class": "io.helidon.security.Security",
|
||||
"ifaces": [
|
||||
"io.helidon.security.Security"
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2018, 2020 Oracle and/or its affiliates. All rights reserved.
|
||||
Copyright (c) 2018, 2020 Oracle and/or its affiliates.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -35,7 +35,6 @@
|
||||
<module>tck-health</module>
|
||||
<module>tck-metrics</module>
|
||||
<module>tck-messaging</module>
|
||||
<module>tck-fault-tolerance</module>
|
||||
<module>tck-jwt-auth</module>
|
||||
<module>tck-openapi</module>
|
||||
<module>tck-opentracing</module>
|
||||
@@ -68,4 +67,13 @@
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>tck-ft</id>
|
||||
<modules>
|
||||
<module>tck-fault-tolerance</module>
|
||||
</modules>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
|
||||
<!--
|
||||
|
||||
Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved.
|
||||
Copyright (c) 2018, 2020 Oracle and/or its affiliates.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -21,11 +21,11 @@
|
||||
<!--
|
||||
- We run these manually as some tests can easily fail on a loaded
|
||||
- system like those in our CI/CD pipeline.
|
||||
- No longer commented out - use 'tck-ft' profile to run these tests
|
||||
-->
|
||||
<test name="microprofile-fault-tolerance 2.0 TCK">
|
||||
<packages>
|
||||
<!-- package name="org.eclipse.microprofile.fault.tolerance.tck.*">
|
||||
</package -->
|
||||
<package name="org.eclipse.microprofile.fault.tolerance.tck.*"/>
|
||||
</packages>
|
||||
</test>
|
||||
</suite>
|
||||
|
||||
@@ -79,7 +79,7 @@ public final class Mp1Main {
|
||||
//Main.main(args);
|
||||
|
||||
Server server = Server.builder()
|
||||
.port(0)
|
||||
.port(7001)
|
||||
.applications(new JaxRsApplicationNoCdi())
|
||||
.retainDiscoveredApplications(true)
|
||||
.basePath("/cdi")
|
||||
|
||||
18
tests/integration/native-image/mp-3/README.md
Normal file
18
tests/integration/native-image/mp-3/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
#GraalVM native image integration test MP-3
|
||||
_____
|
||||
|
||||
This is a manual (for the time being) test of integration with native-image.
|
||||
|
||||
To run this test:
|
||||
|
||||
```shell script
|
||||
export GRAALVM_HOME=${path.to.graal.with.native-image}
|
||||
mvn clean package -Pnative-image
|
||||
./target/helidon-tests-native-image-mp-3
|
||||
```
|
||||
|
||||
Requires at least GraalVM 20.0.0
|
||||
|
||||
This test validates that Quickstart can run on native image with minimal number of changes - eventually with no changes.
|
||||
|
||||
|
||||
81
tests/integration/native-image/mp-3/pom.xml
Normal file
81
tests/integration/native-image/mp-3/pom.xml
Normal file
@@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright (c) 2019, 2020 Oracle and/or its affiliates.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>io.helidon.applications</groupId>
|
||||
<artifactId>helidon-mp</artifactId>
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
<relativePath>../../../../applications/mp/pom.xml</relativePath>
|
||||
</parent>
|
||||
<groupId>io.helidon.tests.integration</groupId>
|
||||
<artifactId>helidon-tests-native-image-mp-3</artifactId>
|
||||
<name>Helidon Integration Tests GraalVM Native image MP3</name>
|
||||
|
||||
<description>
|
||||
This test uses quickstart application with minimal number of changes
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.helidon.microprofile.bundles</groupId>
|
||||
<artifactId>helidon-microprofile</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss</groupId>
|
||||
<artifactId>jandex</artifactId>
|
||||
<scope>runtime</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.activation</groupId>
|
||||
<artifactId>javax.activation-api</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-libs</id>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jboss.jandex</groupId>
|
||||
<artifactId>jandex-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-index</id>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2020 Oracle and/or its affiliates.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.helidon.tests.integration.nativeimage.mp3;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import javax.enterprise.context.RequestScoped;
|
||||
import javax.inject.Inject;
|
||||
import javax.json.Json;
|
||||
import javax.json.JsonBuilderFactory;
|
||||
import javax.json.JsonObject;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.PUT;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.eclipse.microprofile.openapi.annotations.enums.SchemaType;
|
||||
import org.eclipse.microprofile.openapi.annotations.media.Content;
|
||||
import org.eclipse.microprofile.openapi.annotations.media.Schema;
|
||||
import org.eclipse.microprofile.openapi.annotations.parameters.RequestBody;
|
||||
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;
|
||||
import org.eclipse.microprofile.openapi.annotations.responses.APIResponses;
|
||||
|
||||
/**
|
||||
* A simple JAX-RS resource to greet you. Examples:
|
||||
*
|
||||
* Get default greeting message:
|
||||
* curl -X GET http://localhost:8080/greet
|
||||
*
|
||||
* Get greeting message for Joe:
|
||||
* curl -X GET http://localhost:8080/greet/Joe
|
||||
*
|
||||
* Change greeting
|
||||
* curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:8080/greet/greeting
|
||||
*
|
||||
* The message is returned as a JSON object.
|
||||
*/
|
||||
@Path("/greet")
|
||||
@RequestScoped
|
||||
public class GreetResource {
|
||||
|
||||
private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap());
|
||||
|
||||
/**
|
||||
* The greeting message provider.
|
||||
*/
|
||||
private final GreetingProvider greetingProvider;
|
||||
|
||||
/**
|
||||
* Using constructor injection to get a configuration property.
|
||||
* By default this gets the value from META-INF/microprofile-config
|
||||
*
|
||||
* @param greetingConfig the configured greeting message
|
||||
*/
|
||||
@Inject
|
||||
public GreetResource(GreetingProvider greetingConfig) {
|
||||
this.greetingProvider = greetingConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a wordly greeting message.
|
||||
*
|
||||
* @return {@link javax.json.JsonObject}
|
||||
*/
|
||||
@SuppressWarnings("checkstyle:designforextension")
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public JsonObject getDefaultMessage() {
|
||||
return createResponse("World");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a greeting message using the name that was provided.
|
||||
*
|
||||
* @param name the name to greet
|
||||
* @return {@link javax.json.JsonObject}
|
||||
*/
|
||||
@SuppressWarnings("checkstyle:designforextension")
|
||||
@Path("/{name}")
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public JsonObject getMessage(@PathParam("name") String name) {
|
||||
return createResponse(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the greeting to use in future messages.
|
||||
*
|
||||
* @param jsonObject JSON containing the new greeting
|
||||
* @return {@link javax.ws.rs.core.Response}
|
||||
*/
|
||||
@SuppressWarnings("checkstyle:designforextension")
|
||||
@Path("/greeting")
|
||||
@PUT
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@RequestBody(name = "greeting",
|
||||
required = true,
|
||||
content = @Content(mediaType = "application/json",
|
||||
schema = @Schema(type = SchemaType.STRING, example = "{\"greeting\" : \"Hola\"}")))
|
||||
@APIResponses({
|
||||
@APIResponse(name = "normal", responseCode = "204", description = "Greeting updated"),
|
||||
@APIResponse(name = "missing 'greeting'", responseCode = "400",
|
||||
description = "JSON did not contain setting for 'greeting'")})
|
||||
public Response updateGreeting(JsonObject jsonObject) {
|
||||
|
||||
if (!jsonObject.containsKey("greeting")) {
|
||||
JsonObject entity = JSON.createObjectBuilder()
|
||||
.add("error", "No greeting provided")
|
||||
.build();
|
||||
return Response.status(Response.Status.BAD_REQUEST).entity(entity).build();
|
||||
}
|
||||
|
||||
String newGreeting = jsonObject.getString("greeting");
|
||||
|
||||
greetingProvider.setMessage(newGreeting);
|
||||
return Response.status(Response.Status.NO_CONTENT).build();
|
||||
}
|
||||
|
||||
private JsonObject createResponse(String who) {
|
||||
String msg = String.format("%s %s!", greetingProvider.getMessage(), who);
|
||||
|
||||
return JSON.createObjectBuilder()
|
||||
.add("message", msg)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.helidon.tests.integration.nativeimage.mp3;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.eclipse.microprofile.config.inject.ConfigProperty;
|
||||
|
||||
/**
|
||||
* Provider for greeting message.
|
||||
*/
|
||||
@ApplicationScoped
|
||||
public class GreetingProvider {
|
||||
private final AtomicReference<String> message = new AtomicReference<>();
|
||||
|
||||
/**
|
||||
* Create a new greeting provider, reading the message from configuration.
|
||||
*
|
||||
* @param message greeting to use
|
||||
*/
|
||||
@Inject
|
||||
public GreetingProvider(@ConfigProperty(name = "app.greeting") String message) {
|
||||
this.message.set(message);
|
||||
}
|
||||
|
||||
String getMessage() {
|
||||
return message.get();
|
||||
}
|
||||
|
||||
void setMessage(String message) {
|
||||
this.message.set(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.helidon.tests.integration.nativeimage.mp3;
|
||||
|
||||
import javax.enterprise.context.ApplicationScoped;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import io.helidon.microprofile.server.RoutingPath;
|
||||
import io.helidon.security.Security;
|
||||
import io.helidon.webserver.Routing;
|
||||
import io.helidon.webserver.Service;
|
||||
|
||||
/**
|
||||
* Reactive webserver service.
|
||||
* Supports only injection of {@link javax.enterprise.context.ApplicationScoped} beans.
|
||||
*/
|
||||
@ApplicationScoped
|
||||
@RoutingPath("/reactive")
|
||||
public class ReactiveService implements Service {
|
||||
@Inject
|
||||
private Security security;
|
||||
|
||||
@Override
|
||||
public void update(Routing.Rules rules) {
|
||||
rules.get("/", (req, res) -> res.send("Security: " + security));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Quickstart MicroProfile example.
|
||||
*/
|
||||
package io.helidon.tests.integration.nativeimage.mp3;
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
-->
|
||||
|
||||
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
|
||||
http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
|
||||
version="2.0"
|
||||
bean-discovery-mode="annotated">
|
||||
</beans>
|
||||
@@ -14,4 +14,10 @@
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
io.helidon.integrations.cdi.hibernate.HibernateFeatureProvider
|
||||
# Application properties. This is the default greeting
|
||||
app.greeting=Hello
|
||||
|
||||
# Microprofile server properties
|
||||
#server.port=7001
|
||||
server.port=0
|
||||
server.host=0.0.0.0
|
||||
@@ -0,0 +1,37 @@
|
||||
#
|
||||
# Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
# Example Logging Configuration File
|
||||
# For more information see $JAVA_HOME/jre/lib/logging.properties
|
||||
|
||||
# Send messages to the console
|
||||
handlers=io.helidon.common.HelidonConsoleHandler
|
||||
|
||||
# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread
|
||||
java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n
|
||||
|
||||
# Global logging level. Can be overridden by specific loggers
|
||||
.level=INFO
|
||||
|
||||
# Component specific log levels
|
||||
#io.helidon.webserver.level=INFO
|
||||
#io.helidon.config.level=INFO
|
||||
#io.helidon.security.level=INFO
|
||||
#io.helidon.microprofile.level=INFO
|
||||
#io.helidon.common.level=INFO
|
||||
#io.netty.level=INFO
|
||||
#org.glassfish.jersey.level=INFO
|
||||
#org.jboss.weld=INFO
|
||||
@@ -39,6 +39,7 @@
|
||||
<module>se-1</module>
|
||||
<module>mp-1</module>
|
||||
<module>mp-2</module>
|
||||
<module>mp-3</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
|
||||
Reference in New Issue
Block a user