I'm coding a Spring Web Service, using Jackson by default. I'm using #JsonView to indicate which property I need to be parsed to my JSON object. So, the problem is: Many objects are used in different classes, but not exactly all its properties, for example:
class Professor {
#JsonView({Views.Public.class, Views.Internal.class})
private int id;
#JsonView(Views.Internal.class)
private String name;
...
}
class Classroom {
#JsonView({Views.Public.class, Views.Internal.class})
private int id;
#JsonView(Views.Internal.class)
private String name;
...
}
class Lecture {
#JsonView(Views.Public.class)
private Professor professor;
#JsonView(Views.Public.class)
private Classroom classroom;
...
}
What if I need more than two 'perspectives', I'd have to create more interfaces/classes to do that? (like Views.Professor, Views.Principal, ...) Is this a real good practice?
I'd like to hear some suggestions or alternatives to solve that. I'm a little bit confused about being on the right track.
Generic names
You always can define more views if you need more perspectives, that's the idea behind the Jackson JSON views and that's what makes it flexible.
If you use generic names in your views classes, such as Basic, Extended, Public, Private and so on, you'll find it easier to reuse them across multiple beans.
Inheritance
You always can rely on inheritance with #JsonView. Consider the following example where Views.Private extends Views.Public:
public class Views {
interface Public {}
interface Private extends Public {}
}
Serialization of properties annotated with #JsonView(Views.Private.class) will also include properties annotated with #JsonView(Views.Public.class).
Related
Good afternoon, This is my first question here on StackOverflow.
I'm not an expert with the Spring framework and sometimes i get lost for a lot of time for problems that are relatively easy to solve, but this time i can't really get out of it.
I'm trying to implement a method inside a custom Spring Data Repository that should work with multiple Entities and perform some operations on the database, based on the presence of particular annotations on Entity's fields.
I've tried a lot of workarounds found on the internet but i'm not actually able to achieve the result i need. I'll try to be more specific:
This is an example Entity with the annotations:
#Data
#Entity
#MyAnnotation
public class User{
#Id
#MyDataAnnotation
private Long id;
#MyDataAnnotation
private String firstName;
#MyDataAnnotation
private String lastName;
private String userName;
private int followers;
private int following;
}
I have then inside the UserService class something like this:
#Service
public class UserService {
private final UserRepository repository;
public void doSomethingOnUser(Long id){
repository.myCustomMethod(id);
}
}
For the UserRepository i did something like this, just very basic stuffs:
#Repository
public interface UserRepository extends CrudRepository<User,Long>,MyCustomRepository<User,Long> {}
The i have the custom repo interface:
public interface MyCustomRepository<T,ID>{
public void myCustomMethod(ID id);
}
And finally the implementation of myCustomMethod:
public class MyCustomRepositoryImpl <T,ID> implements MyCustomRepository{
#PersistenceContext
EntityManager entityManager;
#Override
public void myCustomMethod(Object id){
User user = entityManager.find(User.class,id);
List<Field> markedFields = MyAnnotationProcessor.getAnnotated(user.getClass());
//Here I'll manipulate the fields that i've obtained
...
entityManager.persist(u);
//And then i'm persisting the modified entity
}
}
This is actually working with the User Entity, but i need to find a way to have it working for every domain type managed by a repository that extends MyCustomRepository.
For example if i have:
public interface WhateverRepository extends CrudRepository<WhateverClass,Long>,MyCustomRepository<WhatheverClass,Long>
myCustomMethod should do his stuffs anyway.
One thing i tried was to retrieve a Class<T> instance with this piece of code:
private final Class<T> type;
public MyCustomRepositoryImpl(Class<T> type) {
this.type = type;
}
And using type instead of User.class but it fails to load the ApplicationContext:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'java.lang.Class<?>' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}`
Thanks if you've read till here, hope you can give me some hints and if I wasn't clear enough please don't hesitate to ask me for further informations.
Update:
Following #amineT answer i tried to use the GenericTypeResolver provided by Spring, but instead of the types i actually get null.
The documentation states that if null is returned, it means that it wasn't able to resolve the type.
This is the code i used:
private final Class<?>[] genericType;
public MyCustomRepositoryImpl(){
this.genericType = GenericTypeResolver.resolveTypeArguments(getClass(), MyCustomRepositoryImpl.class);
}
I think that somehow this "problem" is related to all the proxying that Spring is doing under the hood, but i don't have any precise idea at the moment.
If someone has any clues please write it down here, it'll be appreciated.
I had a similar problem and this answer helped me out. You're geting the NoSuchBeanDefinitionException because you're trying to inject a class type field but you didn't create one in Spring context. What you need to do is use Spring's GenericTypeResolver to find the generic type and process your data accordingly.
Hope this helps
Actually, referencing from the answer pointed by #amineT, I've created a sample project to see if it suits your problem.
From my understanding, what you want should be to determine the type of the bean at runtime not the type of CustomRepositoryImpl. After I built my sample project, I find that your code is almost correct.
Here is a sample of what I would do to your code to make it work:
#Override
public void myCustomMethod(Class cls, Object id){
Object user = entityManager.find(cls,id);
List<Field> markedFields = MyAnnotationProcessor.getAnnotated(cls);
//Here I'll manipulate the fields that i've obtained
...
entityManager.persist(u);
//And then i'm persisting the modified entity
}
Also, here is my github for the sample project I've created.
I've asked yesterday about the instance generation of java object like Entity as the instance variable. https://stackoverflow.com/questions/42239761/declare-entity-in-java-as-private
I am not satisfied for the answers I get and now I want to more clarify what my question is:
I have Entity called User.java:
#Entity(naming = NamingType.SNAKE_LOWER_CASE)
public class User{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
And I have a class called UserImpl.java what I did is:
public class UserImpl implements UserLogic {
private User userEntity = new User(); ------> // Bad practice
/** Methods **/
}
As you can see I declared an instance for User entity in UserImpl class. Is that a bad practice at all?
Any answers will be much appreciated.
The simple act of creating a private instance of a class in another class is not a bad practice at all. In fact, it is very common and Java would really be pointless if you couldn't do this.
I feel like there is still some missing information here. Depending on the function of the "UserImpl" class, this might be a bad practice. But this would entirely depend on how you go about implementing the "UserImpl" class.
For example, if you were planning on creating a variety of methods in the "UserImpl" class that would all center around changing "userEntity," then that might be a bad idea because all of those methods could instead go into the "User" class itself, which would be much simpler and more intuitive.
tldr: This isn't bad practice as it is right now, but depending on the purpose of your "UserImpl" class, it could turn out to be.
I recently came across a part of code which has annotation #PortableProperty used for variables declared in a DTO. Can anyone please explain what it does and the need for using it?
Portable marks a class as being eligible for use by a PofAnnotationSerializer. This annotation is only permitted at the class level and is a marker annotation with no members. The following class illustrates how to use Portable and PortableProperty annotations.
A PortableProperty marks a member variable or method accessor as a POF serialized attribute. Whilst the value() and codec() can be explicitly specified they can be determined by classes that use this annotation. Hence these attributes serve as hints to the underlying parser.
Quoted this from doc found here and here. Check this for more details.
Example:
public class Book
extends ExternalIdEntity
implements Serializable, PortableObject {
#PortableProperty(1)
private String id;
#PortableProperty(3)
private String parentId;
#PortableProperty(4)
private String name;
#PortableProperty(5)
private String legalEntityId;
...
}
Is there some way of using magic methods in Java like there is in PHP with __call?
For instance:
class foo {
#Setter #Getter
int id;
#Getter
Map <String, ClassInFoo> myMap;
protected class ClassInFoo {
#Setter #Getter
String name;
}
#Setter
String defaultKey;
}
I'm using Project Lombok annotations for getter and setter methods to simplify the code.
Let's consider that that my map contains several items mapped by String and the defaultKey defines the default one.
What I would like is to be able to call foo.getName() which would return the default name as foo.myMap.get(defaultKey).getName().
The reason I can't just write all the getters manually is that the Foo class is in fact inherited with generics and the the inner class might be different.
I sort of need something like:
function Object __call(method) {
if (exist_method(this.method)
return this.method();
else
return this.myMap.get(defaultKey).method();
}
Is this somehow possible in Java?
EDIT:
I made a more precise example of what I am trying to achieve here: https://gist.github.com/1864457
The only reason of doing this is to "shorthand" the methods in the inner class.
You absolutely can through reflection by using its features like
public Method getMethod(String name, Class<?>... parameterTypes)
that can be used to see if a class has some methods defined but I don't see how your problem couldn't be solved with a proper use of interfaces, inheritance and overriding of methods
Features like reflection are provided to manage certain, otherwise unsolvable, issues but Java is not PHP so you should try to avoid using it when possible, since it's not in the philosophy of the language.
Isn't it the whole point of inheritance and overriding?
Base class:
public Object foo() {
return this.myMap.get(defaultKey).method();
}
Subclass:
#Overrides
public Object foo() {
return whateverIWant;
}
I'm creating a JAX-WS type webservice, with operations that return an object WebServiceReply. The class WebServiceReply itself contains a field of type Object. The individual operations would populate that field with a few different data-types, depending on the operation.
Publishing the WSDL (I'm using Netbeans 6.7), and getting a ASP.NET application to retrieve and parse the WSDL was fine, but when I tried to call an operation, I would receive the following exception:
javax.xml.ws.WebServiceException: javax.xml.bind.MarshalException
- with linked exception:
[javax.xml.bind.JAXBException: class [LDataObject.Patient; nor any of its super class is known to this context.]
How do I mark the annotations in the DataObject.Patient class, as well as the WebServiceReply class to get it to work? I haven't been able to fine a definitive resource on marshalling based upon annotations within the target classes either, so it would be great if anybody could point me to that too.
WebServiceReply.java
#XmlRootElement(name="WebServiceReply")
public class WebServiceReply {
private Object returnedObject;
private String returnedType;
private String message;
private String errorMessage;
.......... // Getters and setters follow
}
DataObject.Patient.java
#XmlRootElement(name="Patient")
public class Patient {
private int uid;
private Date versionDateTime;
private String name;
private String identityNumber;
private List<Address> addressList;
private List<ContactNumber> contactNumberList;
private List<Appointment> appointmentList;
private List<Case> caseList;
}
Solution
(Thanks to Gregory Mostizky for his answer)
I edited the WebServiceReply class so that all the possible return objects extend from a new class ReturnValueBase, and added the annotations using #XmlSeeAlso to ReturnValueBase. JAXB worked properly after that!
Nonetheless, I'm still learning about JAXB marshalling in JAX-WS, so it would be great if anyone can still post any tutorial on this.
Gregory: you might want to add-on to your answer that the return objects need to sub-class from ReturnValueBase. Thanks a lot for your help! I had been going bonkers over this problem for so long!
You need to use #XmlSeeAlso so that your JAXB implementation will now to include additional classes as well.
In your case it would go something like this:
#XmlRootElement
#XmlSeeAlso({Patient.class, ....})
public class ReturnValueBase {
}
And also change returnedObject property to be of type ReturnValueBase.