I was hoping following might work:
#Size(min = 1, message = "{my.custom.message}")
private String name;
with ValidationMessages.properties in my source path, alogn with my other text resources:
my.custom.message=it is kinda short
...yet the constraint violation still reads {my.custom.message}
Does one have to do something special to have the ValidationMessages.properties file picked up? And where is this documented please?
Apparently it should work, somehow: https://github.com/gwtproject/gwt/issues/5762
Thanks to TBroyer's reply I managed to make it work in my project.
In a nutshell...
...define MyCustomValidationMessages interface:
public interface MyCustomValidationMessages extends com.google.gwt.i18n.client.ConstantsWithLookup {
#DefaultStringValue("NotNull constraint violated")
#Key("notNull")
String notNull();
#DefaultStringValue("Size constraint violated")
#Key("size")
String size();
}
...create MyCustomValidationMessages.properties right next to it:
notNull=must not be null
size=must be at least {min} characters long
...define MyCustomValidationMessagesResolver class and make it use messages from MyCustomValidationMessages interface:
public class MyCustomValidationMessagesResolver extends AbstractValidationMessageResolver
implements UserValidationMessagesResolver {
public MyCustomValidationMessagesResolver() {
super(GWT.create(MyCustomValidationMessages.class));
}
}
...in your AmazingModule.gwt.xml override use of UserValidationMessagesResolver with MyCustomValidationMessagesResolver:
<replace-with class="amazing.project.client.MyCustomValidationMessagesResolver">
<when-type-is class="com.google.gwt.validation.client.UserValidationMessagesResolver"/>
</replace-with>
...apply the constraints in your DTO bean (note the curly brackets):
public class MyDto {
#NotNull(message = "{notNull}")
#Size(min = 1, message = "{size}")
private String name;
}
Voilá!
Working example is here.
If you are sure you have done everything and it just does not work try deleting GWT's temp folders and restarting your IDE. Sometimes merely rebuilding your project and restarting the codeserver (in Idea) might not be enough. #PITA
Related
I'm fairly sure I'm being some kind of idiot, but for the life of me I can't see it.
I have a large Spring Boot 2.1 application that extensively uses injection of properties through the #Value annotation. This works great, has done for years. But there's one specific, brand-new object where I can't get the values set. They are always null.
I know the problem isn't with the values themselves, because some of the same values inject just fine into other objects. But I just can't see what's wrong with THIS object, and would be grateful for your eyeballs.
The values in this object (which is in the same directory and builds just fine) are always null:
#Service
public class SSOUtil {
private String domain = "https://login.microsoftonline.com/";
private String tenantId = "[deleted guid]";
public static String localEnvironment = "local";
public static String devEnvironment = "dev";
public static String testEnvironment = "test";
public static String prodEnvironment = "prod";
#Value("${actions.PROD.touchnet_azure_ad_client_secret}")
private String clientSecretTouchnetProd;
#Value("${actions.TEST.touchnet_azure_ad_client_secret}")
private String clientSecretTouchnetTest;
#Value("${actions.DEV.touchnet_azure_ad_client_secret}")
private String clientSecretTouchnetDev;
#Value("${actions.touchnet_azure_ad_client_id_dev}")
private String clientIdDev;
#Value("${actions.touchnet_azure_ad_client_id_test}")
private String clientIdTest;
#Value("${actions.touchnet_azure_ad_client_id_prod}")
private String clientIdProd;
#Value("${touchnet.redirectURLDev}")
private String redirectURLDev;
#Value("${touchnet.redirectURLTest}")
private String redirectURLTest;
#Value("${touchnet.redirectURLProd}")
private String redirectURLProd;
private String clientId;
private String clientSecret;
private String redirectURI;
public SSOUtil() {
this.redirectURI = redirectURLTest;
this.clientSecret = clientSecretTouchnetTest;
}
public String getADLoginURL() {
String returnURL = "";
System.out.println(clientIdTest); // always prints null
}
}
The values in this object work just fine, though, and note that one of them is the same #Value as in the other class:
#Service
public class LibraryHelpServiceBean implements LibraryHelpService {
private CourseServiceBean courseServiceBean;
private final RestTemplate restTemplate;
#Value("${actions.libraryhelp_lti_api_key}")
private String apikey;
#Value("${actions.touchnet_azure_ad_client_id_test}")
String clientIdTest;
public LibraryHelpServiceBean(CourseServiceBean courseServiceBean, RestTemplateBuilder restTemplateBuilder) {
this.courseServiceBean = courseServiceBean;
this.restTemplate = restTemplateBuilder.build();
}
public void doesValueWork() {
this.apikey = this.apikey;
System.out.println(this.clientIdTest); // always prints correct value, a guid
}
}
Both objects are initialized in a similar way: either directly or indirectly through the #Autowired annotation in other objects that I use (and which work fine, and have worked fine for ages). Here's the creation of SSOUtil (my problem class):
#RestController
#RequestMapping(value = "/web")
public class SSOLandingController {
#Autowired
private SSOUtil ssoUtil;
[rest of class omitted]
}
And here's the creation of LibraryHelpServiceBean, which is working fine and has all #Values populate correctly:
#Service
public class LibraryHelpStreamServiceBean implements LibraryHelpStreamService {
private LibraryHelpServiceBean libraryHelpServiceBean;
public LibraryHelpStreamServiceBean(LibraryHelpServiceBean libraryHelpServiceBean){
this.libraryHelpServiceBean = libraryHelpServiceBean;
}
}
I have already tried changing the class annotation for SSOUtil from #Service to #Component (and #Configuration, just for the heck of it).
What could be causing the #Values in SSOUtil to come back null even though some of those same #Values populate just fine in other classes?
I'm convinced that I'm missing something obvious. I'm hoping it's something small like a typo. I'm nervous that it's something big, like I've completely misunderstood how Spring IOC works for the past several years.
Thanks for your help.
I tested your case on my computer, but I'm not able to reproduce your problem. When things like this is happening, try something very simple like this
package no.mycompany.springbootapp;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class SSOUtil2 {
#Value("${actions.touchnet_azure_ad_client_id_test}")
private String clientIdTest;
}
Inject this component into your controller, set a breakpoint inside your controller method and inspect the injected instance.
My experience is that some unexplainable cases I've been involved in here on SO, were solved by cleaning the build or wiping the .m2-folder.
I have a field in my entity that holds phone-number. According to the conventions of the project, I need to save it in E.164 format in the DB. At the moment I use #PrePersist and #PreUpdate annotations for changing the phone number to the specified format. This method is good for one or two entities but it becomes very error-prone when you have to repeat it over and over.
I was thinking that it would be awesome if I could put the code in annotation and the annotation reads the fields and changes its value just before the persistence something like what #LastModifiedDate and annotation do. I searched the web for the codes of this annotation but I didn't understand how they managed it.
How I can write an annotation that reads the value of a field and changes it before persistence, and how I can do it before some specific operations like delete (I want to set some params before deleting the object too)
Take a look at EntityListeners.
You can create a listener that checks your custom annotation and triggers the appropriate methods.
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.FIELD)
public #interface TheCustomAnnotation{
}
#Entity
#EntityListeners(TheListener.class)
public class TheEntity {
#TheCustomAnnotation
private String phoneNumber;
public class TheListener {
#PrePersist
public void prePersist(Object target) {
for(Field field : target.getClass().getDeclaredFields()){
Annotation[] annotations = field.getDeclaredAnnotations();
// Iterate annotations and check if yours is in it.
}
}
This is just an example.
#Pattern is a pretty powerful annotation that would be a good fit for validations if you are experienced with regular expressions.
For example,
#Pattern(regexp="^[0-9]{3}-[0-9]{3}-[0-9]{4}$")
private String phoneNumber;
The downside is that this only works for Strings though.
If you are interested more in conversions than validations, you may want to look into #JsonDeserialize if you are using Jackson.
For example:
#JsonDeserialize(using=PhoneNumberDeserializer.class)
private String phoneNumber;
Pattern phonePattern = Pattern.compile("^[0-9]{3}(.+)[0-9]{3}(.+)[0-9]{4}$");
public class PhoneNumberDeserializer extends JsonDeserializer<String> {
#Override
public String deserialize(JsonParser jsonParser,
DeserializationContext deserializationContext)
throws IOException, JsonProcessingException {
String phone = jsonParser.getText();
if (matcher.matches(phone)) {
Matcher matcher = phonePattern.matcher(phone);
for (int i = 1; i < matcher.groupCount(); i++) {
marcher.group(i).replaceAll(".*", "");
}
}
}
}
This will work for any type, not just strings.
Sorry it's a little convoluted, I was having fun reteaching myself.
I'm new to GraphQL and I'm currently implementing a GraphQL API into an established Java code, using GraphQL-SPQR and I'm running into a couple issues when it comes extracting data from hierarchical classes.
The issues that I am running into are as follows.
Firstly I don't if there is an easy way to get all the data associated with a returned node. If there is, this would be most useful for my more complex classes.
Secondly when a method returns an abstract class, I only seem able to request the variables on the abstract class. I'm sure this should be possible I am just hitting my head against a wall.
As a simple example
public abstract class Animal {
private String name;
private int age;
// Constructor
#GraphQLQuery(name = "name")
public String getName() {
return name;
}
// Age getter
}
public class Dog extends Animal {
private String favouriteFood;
// Constructor
#GraphQLQuery(name = "favouriteFood")
public String getFavouriteFood() {
return favouriteFood;
}
}
public class Database {
#GraphQLQuery(name = "getanimal")
public Animal getAnimal(#GraphQLArgument(name = "animalname") String animalname) {
return database.get(name);
}
}
So in my first question what I am currently querying is.
"{animalname(name: \"Daisy\") {name age}}"
This works fine as expected. If you imagine the class however had 10 variables I would like to merely be able to write the equivalent of the following without having to look them up.
"{node(name: \"Daisy\") {ALL}}"
Is this possible?
In terms of my second question.
The follow query, throws an error ('Field 'favouriteFood' in type 'Animal' is undefined')
"{animalname(name: \"Bones\") {name age favouriteFood}}"
likewise (reading Inline Fragments of https://graphql.org/learn/queries/)
"{animalname(name: \"Bones\") {name age ... on Dog{favouriteFood}}}"
throws an error Unknown type Dog
This is annoying as I have a number of sub classes which could be returned and may require handling in different fashions. I think I can understand why this is occuring as GraphQL has no knowledge as to what the true class is, only the super class I have returned. However I'm wondering if there is a way to fix this.
Ultimately while I can get past both these issues by simply serialising all the data to JSON and sending it back, it kind of gets rid of the point of GraphQL and I would rather find an alternate solution.
Thank you for any response.
Apologies if these are basic questions.
Answering my own question to help anyone else who has this issue.
The abstract class needs to have #GraphQLInterface included, as shown below
#GraphQLInterface(name = "Animal ", implementationAutoDiscovery = true)
public abstract class Animal {
private String name;
private int age;
// Constructor
#GraphQLQuery(name = "name")
public String getName() {
return name;
}
// Age getter
}
The following code was found after much solution and was created by the creator of SPQR. Effectively, when setting up your schema you need to declare an interface mapping strategy. The code below can be copied wholesale with only the "nodeQuery" variable being replaced with the service you are using to containing your "#GraphQLQuery" and "#GraphQLMutation" methods.
final GraphQLSchema schema = new GraphQLSchemaGenerator()
.withInterfaceMappingStrategy(new InterfaceMappingStrategy() {
#Override
public boolean supports(final AnnotatedType interfase) {
return interfase.isAnnotationPresent(GraphQLInterface.class);
}
#Override
public Collection<AnnotatedType> getInterfaces(final AnnotatedType type) {
Class clazz = ClassUtils.getRawType(type.getType());
final Set<AnnotatedType> interfaces = new HashSet<>();
do {
final AnnotatedType currentType = GenericTypeReflector.getExactSuperType(type, clazz);
if (supports(currentType)) {
interfaces.add(currentType);
}
Arrays.stream(clazz.getInterfaces())
.map(inter -> GenericTypeReflector.getExactSuperType(type, inter))
.filter(this::supports).forEach(interfaces::add);
} while ((clazz = clazz.getSuperclass()) != Object.class && clazz != null);
return interfaces;
}
}).withOperationsFromSingleton(nodeQuery)// register the service
.generate(); // done ;)
graphQL = new GraphQL.Builder(schema).build();
As this solution took some hunting, I'm going to start a blog soon with the other solutions I've stumbled on.
With regards to having a query that just returns all results. This is not possible in GraphQL. One workaround I might write is to have a endpoint that returns JSON of the entire object and the name of the object, then I can just use ObjectMapper to convert it back.
I hope this helps other people. I'm still looking into an answer for my first question and will update this post when I find one.
we are facing a strange problem and I dont quit understand whats going on and hope someone else already had the same issue and has a clue what is going on.
We wrote a simple REST service making use of #Cachable:
#GetMapping(value = "/get/{" + PARAM_TENANT + "}/{" + PARAM_UID + "}")
#Cacheable(value = GET_ORDERS_BY_UID )
public GetOrdersResponseDto getOrdersByUid(#PathVariable final String tenant, #PathVariable final String uid) {
....
return new GetOrdersResponseDto(createCacheKey(), orderResponseDtos);
}
GetOrdersResponseDto consists of several fields. Some contain instances of custom classes, some lists of them and other simple primitive values.
When the GetOrdersResponseDto response is served from the cache all fields of objects that are stored inside a list AND are located in the objects superclass are filled with null values.
We are using hazelcast as the cache implementation. And our cache config is very basic:
#Component
public class HazelcastConfig extends Config {
#Autowired
public HazelcastConfig(final ConfigClient configClient) {
super();
final GroupConfig groupConfig = getGroupConfig();
final String name = configClient
.getConfigPropertyValueOrThrow("public", "com.orderservice.hazelcast.group.name");
groupConfig.setName("foogroup");
final String password = configClient
.getConfigPropertyValueOrThrow("public", "com.orderservice.hazelcast.group.password");
groupConfig.setPassword(password);
The response class looks as follows:
public class GetOrdersResponseDto implements Serializable {
private String cacheSerial;
private List<OrderResponseDto> orderResponseDtos;
}
And the problems occur only for fields of OrderResponseDto that are part of the super class of OrderResponseDto.
I hope someone can give us an hint what's the cause for this strange behaviour.
Edit: I found out, that the problem only occurs for objects that are stored inside lists...
This is Java behaviour. See https://docs.oracle.com/javase/8/docs/api/java/io/Serializable.html
If your object is serializable and extends an object that is not serializable, then instead of the NotSerializeException which would be useful, the fields of the parent object are only initialized which is why you have them as nulls.
You can prove this in a unit test.
Here's one to reuse - https://github.com/hazelcast/hazelcast-code-samples/blob/master/serialization/hazelcast-airlines/the-code/src/test/java/com/hazelcast/samples/serialization/hazelcast/airlines/V1FlightTest.java
With this class
#Component
public class Sample {
#Value("${my.name}")
public static String name;
}
If I try Sample.name, it is always 'null'. So I tried this.
public class Sample {
public static String name;
#PostConstruct
public void init(){
name = privateName;
}
#Value("${my.name}")
private String privateName;
public String getPrivateName() {
return privateName;
}
public void setPrivateName(String privateName) {
this.privateName = privateName;
}
}
This code works. Sample.name is set properly. Is this good way or not? If not, is there something more good way? And how to do it?
First of all, public static non-final fields are evil. Spring does not allow injecting to such fields for a reason.
Your workaround is valid, you don't even need getter/setter, private field is enough. On the other hand try this:
#Value("${my.name}")
public void setPrivateName(String privateName) {
Sample.name = privateName;
}
(works with #Autowired/#Resource). But to give you some constructive advice: Create a second class with private field and getter instead of public static field.
Soruce of this info is this: https://www.baeldung.com/spring-inject-static-field
Spring uses dependency injection to populate the specific value when it finds the #Value annotation. However, instead of handing the value to the instance variable, it's handed to the implicit setter instead. This setter then handles the population of our NAME_STATIC value.
#RestController
//or if you want to declare some specific use of the properties file then use
//#Configuration
//#PropertySource({"classpath:application-${youeEnvironment}.properties"})
public class PropertyController {
#Value("${name}")//not necessary
private String name;//not necessary
private static String NAME_STATIC;
#Value("${name}")
public void setNameStatic(String name){
PropertyController.NAME_STATIC = name;
}
}
This is my sample code for load static variable
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
#Component
public class OnelinkConfig {
public static int MODULE_CODE;
public static int DEFAULT_PAGE;
public static int DEFAULT_SIZE;
#Autowired
public void loadOnelinkConfig(#Value("${onelink.config.exception.module.code}") int code,
#Value("${onelink.config.default.page}") int page, #Value("${onelink.config.default.size}") int size) {
MODULE_CODE = code;
DEFAULT_PAGE = page;
DEFAULT_SIZE = size;
}
}
For those who want to use ApplicationContext in the main class of a Spring Boot application, you can just use the return value of SpringApplication.run.
Although workarounds may need to be implemented, one should try to avoid them in most scenarios if possible. Spring is great at handling dependency injection and treats most objects as Singletons. This means that Spring can handle the creation of objects for you, and the injection of these objects at runtime. When combining this with the fact that your Spring managed bean is likely a Singleton, the use of static methods and variables is largely unnecessary. You can simply autowire in an instance of the object you are looking for at the constructor level or variable level and reference the non-static version of the method or variable. This is ideal and behaves similarly to a static reference. Non static variables are basically static because you are only ever using one instance of the object in every part of the code and because of dependency injection you are never handling the instantiation of the object, just like with a static reference! Great! Now I'm sure there are instances where you need the work around (i.e. you aren't using dependency injection or class is not a singleton), but try to not use workarounds if possible. Also this is just my 2 cents. Someone may be able to offer 3. (:
public class InjectableClass{
#Value("${my.value}")
private String myString;
public String nonStaticMethod(){
return myString;
}
}
public class LogicClass{
private InjectableClass injectableClass;
#Autowire
public LogicClass(InjectableClass injectableClass){
this.injectableClass = injectableClass;
}
public void logicClassMethod(){
System.out.println("Hey! Here is the value I set on myString: " +
injectableClass.nonStaticMethod() + ". That was
basically like using a static method!");
}
}