I need to replace or remove some chars from user input
Is is possible declare annotation for change value after set?
for example, I have UserDTO class with username field. I want to change Unicode characters.
Please note that I using Spring Data + Web Service
#PostMapping("/register")
public RestResult register(#Valid #RequestBody UserDTO userDTO){
...
}
There are two approaches for this.
You can write the setter for the username object to handle this logic. The caveat of this is any username value passed through your setter will go through your String massaging.
public class UserDTO implements Serializable {
#JsonProperty("username")
private String username;
public void setUsername(String username) {
this.username = username.replace("A", "B");
}
public String getUsername() {
return this.username;
}
}
Another possible way of doing this is by using the #JsonCreator annotation provided by Jackson.
You'll need to keep in mind that this will become the deserialization strategy across all objects using the UserDTO object. But considering that you are looking to swap out unicode(most likely to an internal readable format) I would imagine that this would fit your use case.
public class UserDTO implements Serializable {
private String username;
#JsonCreator
public UserDTO(#JsonProperty("username") String username) {
this.username = username.replace("A", "B");
}
public String getUsername() {
return this.username;
}
}
So when passed through into your method, "ABC" will resolve to "BBC". This may be the preferred approach in your case, since it would give you the flexibility to adjust the object when needed without going through your username String cleaning. Objects created by serialization and constructor will go through the cleaning, but the setter will take the value as is. It's easy to get bit by logic in getters and setters.
Related
I am trying to use a custom type with QueryDSL, something like this:
public class Email implements Comparable<Email> {
public String name;
public String domain;
#Override
public int compareTo(Email o) {
return toString().compareTo(o.toString());
}
#Override
public String toString() {
return name + "#" + domain;
}
}
I then have a QueryDSL entity that uses this custom type:
#Entity
public class Record {
public Email email;
public String text;
}
I can then build Queries like this:
BooleanExpression withEmail(Email email)
{
QRecord Q = QRecord.record;
BooleanExpression pred = Q.email.eq(email);
return pred;
}
However, when using MongodbSerializer, the query ends up setting the Email type in a mongo DBObject, and later I get an exception from the mongo driver saying that Email cannot be serialized.
java.lang.RuntimeException: json can't serialize type : class Email
If I annotated by email field in my Record like this:
#Entity
public class Record {
#QueryType(PropertyType.STRING)
public Email email;
public String text;
}
Then it starts working - although I have to manipulate the email with a email as strings in my query constructions instead of the email objects themselves, ex. QRecord.record.email.eq(myEmail.toString()) instead of simply QRecord.record.email.eq(myEmail) like before.
My issue with this solution is that anyone using the Email object has to know that they should annotate it when embedding it inside another object.
Question: is there a way to annotate the Email class in such a way that it will always be serialized as a string entity - or is there a better way to achieve this altogether?
Is there any reason to do not use hierarchy from an entity/model in order to create a dto/form object which help you to hold form search fields?
This is not a big system and these approach will help us to create real dto later if it is needed.
Our models are simple POJO's with almost any logic, maybe some validation logic but that would be valid also for the DTO.
I do not make sense to create a new DTO object with all the fields.
public class User {
private String name;
private String email;
private Date onboardingDate;
public User() {}
public User(String name, String email, Date onboardingDate) {
this.name = name;
this.email = email;
this.onboardingDate = onboardingDate;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public Date getOnboardingDate() { return onboardingDate; }
public void setOnboardingDate(Date onboardingDate) { this.onboardingDate = onboardingDate; }
}
my DTO class, I can use it for use creation and for search purpose.
public class UserDTO extends User {
private Date fromDate;
private Date toDate;
public Date getFromDate() { return fromDate; }
public void setFromDate(Date fromDate) { this.fromDate = fromDate; }
public Date getToDate() { return toDate; }
public void setToDate(Date toDate) { this.toDate = toDate; }
public User convertToEntity() {
return new User(super.getName(), super.getName(), super.getOnboardingDate());
}
}
Thanks fox!
Usually, a DTO will be a subset of the entity data or also contain data from other associations in sub-DTOs or directly embedded in that DTO. If the DTO extends the entity, a user of a DTO object will have the possibility to invoke a getter to access all that state.
If your DTO is really a DTO, it will only have a subset of the data, but by extending from the entity, it might happen by accident that you access data that wasn't part of the subset that was loaded.
Imagine your user entity has detailed contact and address information. For one use case, you need that data, but for another you don't. It would not make sense to expose getters/setter for state that isn't there, would it? This is why one usually creates a separate DTO class for that purpose. You can still work with the entity type if you want to persist/update data, but even for these use cases, people sometimes tend to use DTOs because the persistent state does not necessarily represent the state which can be updated in a use case. This is especially important when you have state for e.g. denormalizations in your persistent state or cross cutting concerns like statistics or audit data.
If your model is so simple and will stay this way, then just use the entity model. If in 90% of the your use cases you need all data anyway, there is nothing you can gain from using DTOs.
Considering you have the need to create a subset of the entity state for your use cases I can only recommend you not to extend from the entity model and really just model what your use case requires. Never expose accessors to state that isn't there in DTOs. That will save you hours of debugging later.
Of course you could use your DTO for filter purposes, that's what is usually called filter by example, but you will notice that this has certain limits and quirks, so at some point you will need a different approach.
You can make use of a library that I develop called Blaze-Persistence Entity Views which allows you to create DTOs as interfaces. This is not only an easier way to model DTOs, but it will also perform better because it will only fetch the state really necessary for the desired representation.
So I have this problem that actually occurs a lot in my code but here's the easiest example of it. The problem is I have an object which contains a list of Strings which correspond to the 'name' or 'id' or 'username' (it depends) fields of another object. So, for example, I have a PublishGroupType object which looks like this:
public class PublishGroupType {
protected List<String> username;
protected String name;
public List<String> getUsername() {
if (username == null) {
username = new ArrayList<String>();
}
return this.username;
}
public String getName() {
return name;
}
public void setName(String value) {
this.name = value;
}
//etc...
}
and a UserModel object that looks like this:
public class UserModel {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
userData.put(UserColumns.USERNAME.getUserColumnName(), username);
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
userData.put(UserColumns.PASSWORD.getUserColumnName(), password);
}
//etc
}
Now because of other reasons I am not allowed to make major changes to PublishGroupType so I cannot directly change the list to contain a list of UserModels instead of Strings. But, I can add a Group field to UserModel and I can create a wrapper class GroupModel which looks like this:
public class GroupModel{
public PublishGroupType publishGroupType;
public List<UserModel> users;
public GroupModel(PublishGroupType publishGroup) {
this.publishGroupType = publishGroup;
List<UserModel> allUsers = userManagementClient.getAllUsers();
//populate the users here from a list of all users
for(UserModel user : userManagementClient.getAllUsers()){
if(publishGroupType.getUsername().contains(user.getUsername())){
users.add(user);
user.setGroup(this);
}
}
}
}
Now, the problem is there are many times more users in the list of all users than there are in a Group, so this is really inefficient to loop through all users for each group. Keep in mind that this is one small and simple example of a problem that happens A LOT all over my code base. Is there a better way to match UserModels with their string Usernames?
First, I'm a little confused as to whether your question is generic like the title of your post:
compare a list of strings to a list of objects with a string field
or if it's specific like the last line in your post:
Is there a better way to match UserModels with their string Usernames?
I'm going to answer the latter.
Here's what I would suggest - have the userManagementClient maintain a HashMap whose keys are the usernames and whose values are the UserModel objects. Then you can modify the class (not sure of the name, you didn't provide it) whose instance you called userManagementClient to provide a method to get the UserModel based on a String parameter (the username):
public UserModel getUserModel(String username){
return userMap.get(username);
}
Then you can change your loop from this:
for(UserModel user : userManagementClient.getAllUsers()){
if(publishGroupType.getUsername().contains(user.getUsername())){
users.add(user);
user.setGroup(this);
}
}
to this:
for(String user : publishGroupType.getUsername()){
UserModel userModel = userManagementClient.getUserModel(user);
if(userModel != null){
users.add(user);
user.setGroup(this);
}else{
//handle missing user appropriately
}
}
Now you're only looping through the users associated with the publishGroupType instead of all the users and you're able to obtain the UserModel without using contains over and over.
One final thought - this question probably would have been a better fit for codereview.stackexchange.com since the code works without errors.
I am using Spring #RequestBody to map a JSON payload to a Java Object. Unfortunately this JSON payload does not use a set convention but rather has names that use both camelCase and snake_case.
To be clear my Controller looks like this:
#RequestMapping(value="/mobile/device", method = RequestMethod.PUT)
public ResponseEntity<Object> flagDevice (#RequestBody List<MobileDeviceData> deviceInfoList) {
... code here ...
}
with the MobileDeviceData Entity object having several setter methods like:
public void setDeviceName(String deviceName) {
this.deviceName = deviceName;
}
public void setFlagId(int flagId) {
this.flagId = flagId;
}
This works great and without any extra effort when the JSON objects name is camelCase. However for snake_case names I need to add the Annotation:
#JsonProperty("flag_id")
private int flagId;
in order for it to be picked up.
I know it's not a good idea to use the #JsonProperty if it can be avoided as you then will need to annotate every parameter. My question is, is there a more general way to enforce matching snake_case with the corresponding camelCase in the Entity object? And obviously to do it without screwing up the ones that are already camelCase.
As per the article here, there is a simple approach to deserialize the MobileDeviceData class. Here is the sample code as below:
#JsonDeserialize(using = UserDeserializer.class)
public class User {
private ObjectId id;
private String username;
private String password;
public User(ObjectId id, String username, String password) {
this.id = id;
this.username = username;
this.password = password;
}
public ObjectId getId() { return id; }
public String getUsername() { return username; }
public String getPassword() { return password; }
}
Assume User is the class we’re interested in writing the Deserializer for. Not much is notable here, except for the annotations that tell Jackson who knows how deserialize this class.
public class UserDeserializer extends JsonDeserializer {
#Override
public User deserialize(JsonParser jsonParser,
DeserializationContext deserializationContext) throws IOException {
ObjectCodec oc = jsonParser.getCodec();
JsonNode node = oc.readTree(jsonParser);
return new User(null,
node.get("username").getTextValue(),
node.get("password").getTextValue());
}
}
The deserializer is created by extending Jackson’s abstract JsonDeserializer class, and giving it the type we want to deserialize to. Difficult is figuring out that you can reference the JSON by field name with the JsonParser's ObjectCodec.
I hope it helps.
Please feel free to comment if needed!
Having been working on this a bit, I now realize doing anything like what was requested would be counterproductive.
When you receive (deserialize) a JSON Object, it is generally expected that you will deliver (serialize) with the same parameters. If an implementation extracted both camelCase and underscore parameters the same way, then it would not know how to deserialize correctly later on. By following a standard convention and then using #JsonProperty for all the exceptions, it remains possible to deserialize and later deliver the JSON object just as it was received.
I want to mapping a class to a primitive type
#Entity
#Table(name="PERSON")
public class Person implements Serializable {
...
private Email email = null;
...
#Column(name="email")
public Email getEmail() {
return email;
}
public void setEmail(Email email) {
this.email=email;
}
}
In this example I want to save the email like a String
I wish something like:
interface someInterface{
String getValue();
void setValue(String p);
}
Then if I implement this interface in Email it can be save and loaded transparently (I haven't find something like this).
I don't want to serialize the class
I use Email as a example, but I have in mind many other class, to little to be a whole entity.
Any idea?
JPA2.1 provides AttributeConverter which means that a field can be marked with a converter persisting it as, for example, a String. All JPA implementations have their own variant currently, but DataNucleus JPA provides the JPA2.1 feature already, see the foot of this page.
Make two variables. Email which is object and that you mark as #Transient and emailStr that you store in the database. The emailStr getter and setter should be private, and the getEmail creates the email object (lazily) based on the emailStr.
Another solution, if you have email in many entities is to create a custom UserType.
Just google hibernate UserType..
You can use converters in EclipseLink for this,
see,
http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Mapping/Basic_Mappings/Default_Conversions_and_Converters
There's nothing stopping you from using String in your Classes as far as JPA is concerned. Or any other primitive type for that matter...
EDIT: You mean something like this hopefully
#Entity
#Table(name="PERSON")
public class Person implements Serializable {
...
private String email = null;
...
#Column(name="email")
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email=email;
}
}