I have a pojo, which is common for multiple services and each of them has different validation rules for that object. So, I am extending that pojo in each of my services and override some of the setters and throw constraint validations on those overridden methods. The pojo is being constructed from the submitted json over REST call. Jackson is the lib that supposedly should invoke the setter.
#JsonSetter("name")
public void setName(#Length(min = 1, max = 50) #NotBlank String name) {
this.name = name;
}
Here is my REST method declaration:
public ResponseEntity<?> createEntity(#Valid #RequestBody EntityDTO entity) {
It seems that validation doesn't work in particular with Jackson as I see validateParameters method of org.hibernate.validator.internal.engine.ValidatorImpl invoked on the other methods.
This is how my ValidationConfiguration bean like:
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.validation.MessageInterpolatorFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import javax.validation.Validator;
#Configuration
public class ValidationConfiguration {
public ValidationConfiguration() {
}
#Bean(name = "overriddenValidator")
public Validator validator() {
LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
factoryBean.setParameterNameDiscoverer(new CustomParameterNameDiscoverer());
MessageInterpolatorFactory interpolatorFactory = new MessageInterpolatorFactory();
factoryBean.setMessageInterpolator(interpolatorFactory.getObject());
return factoryBean;
}
#Bean
public static MethodValidationPostProcessor methodValidationPostProcessor(Environment environment, #Qualifier("overriddenValidator") Validator validator) {
validator.forExecutables();
MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
boolean proxyTargetClass = (Boolean) environment.getProperty("spring.aop.proxy-target-class", Boolean.class, true);
processor.setProxyTargetClass(proxyTargetClass);
processor.setValidator(validator);
return processor;
}
}
I also do some validation of request parameters and it works well. However, it doesn't work for this setter.
I couldn't make it work on setters, but, weirdly enough, validations kick in on getters. Even though getters are not invoked explicitly. Seems it has to do with Jackson??
#Override
#Length(min = 1, max = 50)
#NotBlank
public String getName() {
return super.getName();
}
Related
Like Spring framework, I want to create a Pointcut to execute some logic before executing the method. Is it possible to do that in Helidon MP?
#Pointcut("execution(public * *(..))")
private void anyPublicOperation(String input) {}
Helidon MP, like all MicroProfile implementations, is centered around CDI, which offers, for this purpose, interceptors and decorators.
I have already done that using Interceptor. Thanks!
Here is the example:
Creating a custom annotation with #InterceptorBinding
#InterceptorBinding
#Target({ElementType.TYPE, ElementType.METHOD})
#Retention(RetentionPolicy.RUNTIME)
public #interface SoapSecure {
String tokenParam() default "token";
}
Creating the interceptor
#Priority(1)
#Interceptor
#SoapSecure
#Slf4j
public class SoapAuthenticationInterceptor {
#Inject
private AuthService authService;
#AroundInvoke
public Object validateToken(InvocationContext invocationContext) throws Exception {
Method method = invocationContext.getMethod();
log.info("Validate the token from SOAP APIs: " + method.getName());
String tokenParam = method
.getAnnotation(SoapSecure.class)
.tokenParam();
Parameter[] params = method.getParameters();
String accessToken = null;
for (Parameter p : params) {
if (p.getName().equals(tokenParam)) {
// validate the access token
authService.validateAccessToken(Objects.toString(method.invoke(p)));
}
}
return invocationContext.proceed();
}
}
Then use it:
#SoapSecure
public boolean test(String token){}
Rest Controller:
#RequestMapping(value = "/admin/rest/new-subscriptions")
public List<NewSubscriptionDTO> getNewSubscriptions() {
NewSubscriptionDTO dto = new NewSubscriptionDTO();
dto.setId("54");
dto.setName("John Doe");
return Arrays.asList(dto);
}
NewSubscriptionDTO:
package dermatica.web.admin.rx;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.joda.time.DateTime;
import java.io.Serializable;
public class NewSubscriptionDTO implements Serializable {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
I get the following exception:
no properties discovered to create BeanSerializer (to avoid exception,
disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
If I annotate the fields with #JsonProperty it work fine.
Is there a way for the serialization to work automatically without needing this annotation?
#JsonProperty auto-generates a getter/setter that Jackson uses to read/write to the fields during serialization/deserialization. Here are some alternative approaches:
Provide your own public getters/setters for all fields
Make the fields public, generally frowned upon, but if you're creating a simple DTO, that may be acceptable.
Setting ObjectMapper Visibility for FIELD to ANY (see here)
Disable the FAIL_ON_EMPTY_BEANS exception (see here)
Given that your DTO class has getters and setters, this should work without #JsonProperty. I wasn't able to reproduce the exact error message you showed, but here are some suggestions that may help:
[Controller] Explicitly specify the method type as GET, either using method = GET or #GetMapping - not necessary, but it's good to be explicit
[Controller] Make sure you annotate the controller class with #RestController, indicating the response is serialized to JSON and wrapped in an HttpResponse object.
[DTO] You don't need to extend Serializable (see here).
The final controller would look like this:
#RestController
public class MyController {
#GetMapping(value = "/admin/rest/new-subscriptions")
public List<MyDTO> getDTO() {
MyDTO dto = new MyDTO();
dto.setId("54");
dto.setName("John Doe");
return Collections.singletonList(dto);
}
}
Response:
[{"id":"54","name":"John Doe"}]
I am trying to implement a custom deserializer.
Because I only want to add functionality to the default deserializer, I tried to store in my custom deserializer the default one: I would like to use the default to deserialize the json and then add other information.
I am trying to use BeanDeserializerModifier to register the custom deserializer.
SimpleModule module = new SimpleModule("ModelModule", Version.unknownVersion());
module.setDeserializerModifier(new BeanDeserializerModifier() {
#Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
JsonDeserializer<?> configuredDeserializer = super.modifyDeserializer(config, beanDesc, deserializer);
if (Document.class.isAssignableFrom(beanDesc.getBeanClass())) {
logger.debug("Returning custom deserializer for documents");
configuredDeserializer = new DocumentDeserializer(configuredDeserializer, (Class<Document>)beanDesc.getBeanClass());
}
return configuredDeserializer;
}
});
As you can see, if the object to generate is a "Document", I am modifying the deserializer returning a custom deserializer. I am passing the default deserializer to the constructor so I can use it later.
When I try to deserialize, Jackson fails with the error:
No _valueDeserializer assigned(..)
I have investigated and it seems that the default deserializer does not have the correct deserializers for its properties: for all the properties, it is using the deserializer FailingDeserializer that, of course, fails and returns the error mentioned above. This deserializer is supposed to be substituted but it is not.
It seems that, after calling the method modifyDeserializer, Jackson completes the configuration.
The custom deserializer that I am using is:
#SuppressWarnings("serial")
public class DocumentDeserializer extends StdDeserializer<Document> {
private JsonDeserializer<?> defaultDeserializer;
private DocumentDeserializer(JsonDeserializer<?> defaultDeserializer, Class<? extends Document> clazz) {
super(clazz);
this.defaultDeserializer = defaultDeserializer;
}
#Override
public Document deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
Document documentDeserialized = (Document) defaultDeserializer.deserialize(jp, ctxt);
/* I want to modify the documentDeserialized before returning it */
return documentDeserialized;
}
}
UPDATE:
I solved the problem using a different Deserializer:
public class CustomDeserializerModifier extends BeanDeserializerModifier {
private static final Logger logger = Logger.getLogger(CustomDeserializerModifier.class);
public CustomDeserializerModifier (Factory factory) {
this.factory = factory;
}
#Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
JsonDeserializer<?> configuredDeserializer;
if (CustomDeserializedNode.class.isAssignableFrom(beanDesc.getBeanClass())) {
Converter<Object, Object> conv = beanDesc.findDeserializationConverter();
JavaType delegateType = conv.getInputType(config.getTypeFactory());
configuredDeserializer = new CustomDeserializedNodeDeserializer(conv, delegateType, (JsonDeserializer<Document>) deserializer,
(Class<? extends CustomDocument<?>>)beanDesc.getBeanClass());
} else {
configuredDeserializer = super.modifyDeserializer(config, beanDesc, deserializer);
}
return configuredDeserializer;
}
#SuppressWarnings("serial")
public class CustomDeserializedNodeDeserializer extends StdDelegatingDeserializer<Object> {
private Class<? extends CustomDocument<?>> beanClass;
public CustomDeserializedNodeDeserializer(Converter<Object,Object> converter,
JavaType delegateType, JsonDeserializer<Document> delegateDeserializer, Class<? extends CustomDocument<?>> beanClass) {
super(converter, delegateType, delegateDeserializer);
this.beanClass = beanClass;
}
#Override
public CustomDeserializedNode deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
CustomDeserializedNode node = (CustomDeserializedNode)factory.createCustomDocument(beanClass);
CustomDeserializedNode documentDeserialized = (Document) super.deserialize(jp, ctxt, node);
return documentDeserialized;
}
}
}
Probably extending StdDelegatingDeserializer does what #StaxMan is suggesting.
This should be added in a FAQ, but what you need to do is to implement 2 interfaces:
ResolvableDeserializer (method resolve(...))
ContextualDeserializer (method createContextual(...))
and delegate these calls to defaultDeserializer in case it implements one or both interfaces. These are required for deserializer initialization; especially ContextualDeserializer through which property annotations are made available to deserializers.
And ResolvableDeserializer is used by BeanDeserializer to get deserializers for properties it has, if any; this is where _valueDeserializer in question is likely to be fetched.
Imagine I have a type Disposable which some classes implement:
class FactoryImpl implements Disposable {}
I can bind this class as a singleton:
bind(Factory.class)
.to(FactoryImpl.class)
.in(Singleton.class);
or as an eager singleton:
bind(Factory.class)
.to(FactoryImpl.class)
.asEagerSingleton();
Note that the implementation has the type, not the interface.
How can I find all singletons which Guice has actually created and which implement the type Disposable?
Note that I don't want to blindly call get() in the provider to avoid to create stuff which I don't need (especially since I'm destroying singletons, so creating new ones might cause problems).
This is the opposite of questions like How can I get all singleton instances from a Guice Injector? which only work then the interface contains the keys that you need.
[EDIT] This is how far I got. Is this code correct?
First, I need my interface.
public interface Disposable {
public void dispose();
}
The magic happens here:
import java.util.Collections;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.beust.jcommander.internal.Lists;
import com.google.inject.AbstractModule;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
import com.google.inject.spi.InjectionListener;
import com.google.inject.spi.TypeEncounter;
import com.google.inject.spi.TypeListener;
import com.google.inject.util.Modules;
/** Support for disposable beans. */
#Singleton
public class DisposableListener implements InjectionListener<Object> {
private static final Logger log = LoggerFactory.getLogger(DisposableListener.class);
/** Use this method to create the injector */
public static Module createModule(Module ...modules) {
/* Create a new module with ourself at the start. That way, our listeners will see all bindings. */
List<Module> list = Lists.newArrayList(new DisposingModule());
Collections.addAll(list, modules);
return Modules.combine(list);
}
/** To dispose all disposables, call this method.
*
* <p>Good places to call this is at the end of {#code main()},
* in an destroy listener of a {#link javax.servlet.ServletContext}, or after a test.
*/
public static void dispose(Injector injector) {
injector.getInstance(DisposableListener.class).disposeAll();
}
/** Everything that is disposable */
private List<Disposable> beans = Lists.newArrayList();
private void disposeAll() {
log.debug("Disposing {} beans", beans.size());
for(Disposable bean: beans) {
try {
bean.dispose();
} catch(Exception e) {
log.warn("Error disposing {}", bean, e);
}
}
}
#Override
public void afterInjection(Object injectee) {
if(injectee instanceof Disposable) {
log.debug("Noticed disposable bean {}", injectee);
beans.add((Disposable) injectee);
}
}
/** Module which creates the {#link DisposableListener} for the injector and sets everything up. */
private static class DisposingModule extends AbstractModule {
#Override
protected void configure() {
DisposableListener disposableListener = new DisposableListener();
/* Attach a type listener to Guice which will add disposableListener to all types which extend Disposable */
bindListener(TypeMatchers.subclassesOf(Disposable.class), new TypeListener() {
#Override
public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
Class<?> clazz = type.getRawType();
log.debug("Found disposable: {}", clazz);
encounter.register(disposableListener);
}
});
/* Add the listener instance to the module, so we can get it later */
bind(DisposableListener.class)
.toInstance(disposableListener);
}
}
}
The code wraps the other modules and makes sure the DisposableListener is installed in the injector early on. Then it listens for new instances which are created and collects them in a list.
The code probably should check that these are all singletons but I don't know how to do that.
Here are the unit tests:
import static org.junit.Assert.*;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import com.beust.jcommander.internal.Lists;
import com.google.common.base.Joiner;
import com.google.inject.AbstractModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Singleton;
public class DisposableListenerTest {
private static List<String> events = Lists.newArrayList();
#Before
public void clearEvents() {
events.clear();
}
#Test
public void testEagerNoGetInstance() {
Injector injector = Guice.createInjector(DisposableListener.createModule(new TestEagerSingleton()));
// No call to getInstance()
DisposableListener.dispose(injector);
assertEvents("Foo created", "Foo disposed");
}
#Test
public void testEagerGetInstance() {
Injector injector = Guice.createInjector(DisposableListener.createModule(new TestEagerSingleton()));
Foo inst1 = injector.getInstance(Foo.class);
Foo inst2 = injector.getInstance(Foo.class);
DisposableListener.dispose(injector);
assertSame(inst1, inst2); // validate singleton
assertEvents("Foo created", "Foo disposed");
}
#Test
public void testLazyNoGetInstance() {
Injector injector = Guice.createInjector(DisposableListener.createModule(new TestLazySingleton()));
// No call to getInstance()
DisposableListener.dispose(injector);
assertEvents();
}
#Test
public void testLazyGetInstance() {
Injector injector = Guice.createInjector(DisposableListener.createModule(new TestLazySingleton()));
Foo inst1 = injector.getInstance(Foo.class);
Foo inst2 = injector.getInstance(Foo.class);
DisposableListener.dispose(injector);
assertSame(inst1, inst2); // validate singleton
assertEvents("Foo created", "Foo disposed");
}
#Test
public void testAnnotation() {
Injector injector = Guice.createInjector(DisposableListener.createModule(new TestLazySingleton()));
FooWithAnnotation inst1 = injector.getInstance(FooWithAnnotation.class);
FooWithAnnotation inst2 = injector.getInstance(FooWithAnnotation.class);
DisposableListener.dispose(injector);
assertSame(inst1, inst2); // validate singleton
assertEvents("FooWithAnnotation created", "FooWithAnnotation disposed");
}
private void assertEvents(String...expectedEvents) {
Joiner joiner = Joiner.on('\n');
String expected = joiner.join(expectedEvents);
String actual = joiner.join(events);
assertEquals(expected, actual);
}
public static class Foo implements Disposable {
public Foo() {
events.add("Foo created");
}
#Override
public void dispose() {
events.add("Foo disposed");
}
}
#Singleton
public static class FooWithAnnotation implements Disposable {
public FooWithAnnotation() {
events.add("FooWithAnnotation created");
}
#Override
public void dispose() {
events.add("FooWithAnnotation disposed");
}
}
public static class TestLazySingleton extends AbstractModule {
#Override
protected void configure() {
bind(Foo.class).in(Singleton.class);
}
}
public static class TestEagerSingleton extends AbstractModule {
#Override
protected void configure() {
bind(Foo.class).asEagerSingleton();
}
}
// TODO test when bean isn't a singleton
}
Don't re-invent scopes
First off, manually "disposing" of singleton Guice bindings is somewhat putting the cart before the horse. Instead of binding objects as singletons and then needing to regularly clean them up, you should use a more appropriate scope (or define your own) so that these objects have natural life cycles for the duration of time that they're expected to exist, such as for a single request or test.
This is evidenced by the documentation on DisposableListener.dispose():
Good places to call this is at the end of main(), in an destroy listener of a ServletContext, or after a test
None of those are place you should need something like this:
When .main() terminates the JVM will soon terminate too (and presumably your injector will go out of scope) so there's generally no need to do any such cleanup before letting the binary terminate.
Similarly when a ServletContext has been destroyed you're generally just about to terminate the JVM, so just let it exit normally.
In tests you should normally be constructing isolated injectors for each test, thereby avoiding any cross-test pollution. When the test ends the injector and all its bindings goes out of scope, and there should be nothing to clean up.
Manage resources separately from Guice
Of course, you could be creating objects that need to be cleaned up, such as an AutoCloseable instance, but that shouldn't be the responsibility of Guice. Generally the .getInstance() call site that obtains the closeable resource should be responsible for cleaning it up. Alternatively the module(s) could be responsible for creating and managing these resources. Then you construct the injector inside a try-with-resources block that manages the lifecycle of the resources module(s).
If those options aren't sufficient and you really need more powerful life cycle semantics use a proper life cycle framework such as Guava's ServiceManager, rather than co-opting Guice into one.
That said, having objects that require cleanup in Guice is itself generally not a good idea. Consider instead binding a wrapper type that allows the caller to open (and close) resources as needed, rather than binding a long-lived stateful resource object directly.
Prefer explicit bindings over Guice listeners
If you really, really need to collect several unrelated objects bound in a Guice injector, do so explicitly at .configure() time, rather than implicitly via introspection. Using a Multibinder allows your modules to explicitly declare which objects need to be disposed of, by binding them to a Multibinder<Disposable> instance which aggregates them all. Then your cleanup step is simply:
for (Disposable resource : injector.getInstance(new Key<Set<Disposable>>() {}) {
resource.dispose();
}
This avoids the "magic" of a listener that silently comes in and cleans up after you, instead allowing module authors to determine how best to handle the resources they bind, and optionally taking advantage of this cleanup functionality if necessary.
I have a class:
#Column(name = "data", nullable = false)
String data;
public void setData(final String data) {
this.data = data;
}
public void setDataAsSet(final Set<String> strings) {
setData(JOINER.join(strings));
}
Can Jackson serialize / de-serialize it?
Ideally I would like to (at least) support de-serialization.
I've searched the web and found no clear answer. Some bug reports, and suggestions to #ignore the 'un-necessary' getter / setter, but I want all of them.
Thanks.
It seems to be possible with writing custom deserializer. Unfortunately have no opportunity to set the env now and try. But in general I don't it's a good idea to send same data as String or Set<String>. It will result in hard to debug bugs or other unpredictable problems. There should be two separately declared fields or it should always be a collection (in most cases it will probably have single element). Rethink it please.
I still encourage You to rethink the design nevertheless did it:
Bean:
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
public class SampleBean {
#JsonDeserialize(using = SampleDeserializer.class)
public String data;
}
Deserializer:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import java.io.IOException;
import java.util.List;
import static com.fasterxml.jackson.core.JsonToken.VALUE_STRING;
public class SampleDeserializer extends JsonDeserializer<String> {
#Override
public String deserialize(JsonParser jp, DeserializationContext ctx) throws IOException {
JsonToken jt = jp.getCurrentToken();
if (jt == VALUE_STRING) {
return jp.getValueAsString();
} else if (jt == JsonToken.START_ARRAY) {
return jp.readValueAs(List.class).toString().replace("[", "").replace("]", "").replaceAll("\\s*", "");// joining could be done much better of course
}
return null;
}
}
Test:
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Assert;
import org.junit.Test;
import java.io.IOException;
public class SampleTest {
#Test
public void test() throws IOException {
final String json = "{\"data\":\"2\"}";
final String json2 = "{\"data\":[\"2\",\"3\"]}";
ObjectMapper om = new ObjectMapper();
SampleBean sb = om.readValue(json, SampleBean.class);
Assert.assertEquals("2", sb.data);
sb = om.readValue(json2, SampleBean.class);
Assert.assertEquals("2,3", sb.data);
}
}