Marshalling a Spring Data Jpa Projection in a rest endpoint to xml produces strange tags - spring-boot

When marshalling a spring data jpa projection, the xml structure is invalid. The proxy is displayed as a root xml tag, not the projection interface class name. The JSON output however is fine, but the rest client on the external system does not understand json.
The entity looks like this example - the real entity is more complicated:
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String surname;
private String city;
private int age;
// getters, setters, ...
}
The projection interface looks like:
#XmlAccessorType(XmlAccessType.PROPERTY)
#XmlRootElement(name = "user-short")
public interface UserShort {
String getName();
String getCity();
}
The response from the rest endpoint shows (we need application/xml):
<.Proxy253>
<name>Alexander</name>
<city>Alexandria</city>
</.Proxy253>
The number in the proxy tag is changing. I would expect a root tag with the name of the interface or the #XmlRootElement(name = "user-short") annotation like this:
<user-short>
<name>Alexander</name>
<city>Alexandria</city>
</user-short>
We are using a interface-based Spring Data JPA projection in our project. Now we want to use it in a REST endpoint, without exposed repositories. So we can't use Spring Data Rest projections. Due to nested projections, we can't use class-based projections either. The JSON output looks like expected, but the xml output writes the proxy class as the root tag. And all XML-Annotations are ignored ( enums don't get converted to ordinals etc. ).
In a debugger when I open the variable of the interface type UserShort I see a instance of type com.sun.proxy.Proxy, some reflection stuff. There is no implementation of UserShort.
What is the prefered way to tell the marshaller to use the information from the interface and not the reflection stuff in spring boot?
Thanks for any help

What you try is not supported by the JAXB spec:
The mapping of existing Java interfaces to schema
constructs is not supported. Since an existing class
can implement multiple interfaces, there is no obvious mapping of existing interfaces to XML schema constructs.
Sou you should use Class-based Projections (DTOs) on Spring Data

Related

how to insert a object in mongodb using spring

required format image
I want to object data into MongoDB using spring and I have hardcoded it.
please how to write a schema for that and I have taken it as an example only.
I have a different type of categories in it I have taken only clothes.
please tell me how to write one schema for a different type of categories and query too.
please find the attachment for your reference
I would recommend going though Spring Data MongoDB documentation for specifics on mapping java objects to MongoDB documents. Your case would look similar to:
#Document
public class Clothes {
#Id
private ObjectId id;
private Men men;
private Women women;
// getters & setters
}
You would need to define each sub class but this should be the gist of it.
What you can do is create a simple POJO (Plain Old Java Object) and with that you can insert that object into the data base. The the following example:
#Document
public class OAuthModel implements Serializable {
#Id
String username;
#Indexed
String oAuthID;
#Indexed
String type;
// Getter and Setters and Construct.
}
When I insert this object in the DB by calling:
OAuthModel authModel = new OAuthModel(username,firebaseToken.getUid(), OAuthHosts.GOOGLE.getType());
oAuthRepo.insert(authModel);
It will then be seen as this in the Database:
Keep in mind this will work no matter what your object looks like, you can have hashmaps etc. The should be a built in serialization.

How do you save files for entity in Spring Data Rest?

In a regular entity for SDR, it takes care of all properties of an entity for you saving it to the database. But how do you handle files?
#Entity
public class User {
String name;
Set<File> myfiles; //how can I make this work?
}
#RepositoryRestResource
public interface UserRepository extends JpaRepository<User, Long> {}
How can I make it so that a User owns a list of files, can upload and download them?
This is not really possible with Spring Data/REST as it focusses on structured data; i.e. tables and associations, for the most part.
#Lob is problematic as it forces you to store your content in the database which isn't necessarily where you want to store it. The file-system or S3 might be better for example.
byte[] is also problematic if you have very large files as you will likely cause OutOfMemoryExceptions.
Instead, there is a community project called Spring Content that addresses exactly the problem you are trying to solve.
Spring Content provides the same programming paradigms as Spring Data/REST for unstructured data; i.e. images, documents, movies, etc. So, using this project you can associate one, or in your case, many "content" objects with your Spring Data entities and manage them over HTTP just like you do with your Spring Data Entities too.
Its pretty simple to add to your project, as follows:
pom.xml (boot starters also available)
<!-- Java API -->
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-fs</artifactId>
<version>1.0.0.M4</version>
</dependency>
<!-- REST API -->
<dependency>
<groupId>com.github.paulcwarren</groupId>
<artifactId>spring-content-rest</artifactId>
<version>1.0.0.M4</version>
</dependency>
Configuration
#Configuration
#EnableFilesystemStores
#Import("org.springframework.content.rest.config.RestConfiguration.class")
public class ContentConfig {
#Bean
FileSystemResourceLoader fileSystemResourceLoader() throws IOException {
return new FileSystemResourceLoader(new File("/path/to/uploaded/files").getAbsolutePath());
}
}
To associate content, modify your User entity as follows:
#Entity
public class User {
String name;
List<Image> images;
}
Add an Image entity:
#Entity
public class Image {
#ContentId
private String contentId;
#ContentLength
private long contentLength = 0L;
#MimeType
private String mimeType = "text/plain";
}
And to this add a "store" (the equivalent of a Repository but for content):
ImageStore.java
#StoreRestResource
public interface ImageStore extends FilesystemContentStore<Image, String> {}
This is all you need to create REST endpoints # /users/{userId}/images. When your application starts, Spring Content will look at your dependencies seeing Spring Content Filesystem, look at your ImageStore interface and inject a filesystem-based implementation of that interface. It will also see the Spring Content REST dependency and inject an #Controller implementation that forwards HTTP requests to your ImageStore. Just like Spring Data does for your UserRepository. This saves you having to implement any of this yourself which I think is what you are after.
So...
To manage content with the injected REST API:
curl -X POST /users/{userId}/images -F file=#/path/to/image.jpg
will store the image on the filesystem at `` and associate it with the user entity whose id is userId.
curl /users/{userId}/images/{contentId} -H "Accept: image/jpeg"
will fetch it again and so on...supports all CRUD methods and video streaming as well BTW!
There are a couple of getting started guides here. The reference guide for Spring Content Filesystem is here. And there is a tutorial video here. The coding bit starts about 1/2 way through.
A couple of additional points:
- if you use the Spring Boot Starters then you don't need the #Configuration for the most part.
- Just like Spring Data is an abstraction, so is Spring Content so you aren't limited to storing your images on the filesystem. You could store them as BLOBs in the database, or in cloud storage like S3.
HTH
I suggest you can use #Lob instead to save file data (fileData variable below)
#Entity
public class File {
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
private String id;
private String fileName;
private String fileType;
#Lob
private byte[] fileData;
}

Service cannot auto-wire in Entity class

I needed a RoleMappingService class(which is annotated by #Service) object into a Employee class (which is annotated by #Entity)
below are my classes
********************* RoleMappingsService class **********************
#Service
public class RoleMappingsService {
#Autowired
RolesMappingDao rolesMappingDao;
public List<RolesMappings> getRolesMappingByauthSystemRole(String authSystemRole) {
return rolesMappingDao.getRolesMappingByauthSystemRole(authSystemRole);
}
}
############### Employee class
#Configurable
#Component
#Entity
#NamedQuery(name = "Employee.findAll", query = "SELECT e FROM Employee e")
public class Employee implements Serializable, UserDetails {
#Autowired
#Transient
RoleMappingsService roleMappingsService;
public static final String STATUS_ACTIVE = "ACTIVE";
public static final String STATUS_INACTIVE = "INACTIVE";
public static final String STATUS_LOCKED = "LOCKED";
public static final String STATUS_ONLEAVE = "ONLEAVE";
public static final String STATUS_EXPIRED = "EXPIRED";
private static final long serialVersionUID = 1L;
#Id
#Column(name = "emp_id")
private String empId;
#Column(name = "emp_password")
private String empPassword;
#Column(name = "emp_email")
private String empEmail;
#Column(name = "emp_address")
private String empAddress;
#Column(name = "emp_age")
private int empAge;
#Column(name = "emp_firstname")
private String empFirstname;
}
Here Autowire is not working for roleMappingsService and the object is always found null. However I tried to autowire same object in some other service and there Autowire is perfectly working.
( I know Entity class is only used for representing database table but in my case I need to set some field values which depend on another table so need to fetch data using service)
JB Nizet is totally right
I'll try to provide more explanations here.
Spring can Autowire only beans, objects that it manages, and not arbitrary objects.
Entities are usually created from within a JPA (Hibernate) and are not something that you want to manage by Spring.
There is a related discussion available here but bottom line you should never do something like this.
Why not?
Here are a couple of questions/reasons:
Maybe these entities will go outside spring context at all (serialization), what should that reference contain? Should we also serialize the service? How?
What will happen if the method that turns to the service will be called "outside" the spring driven application (maybe even in different JVM)?
If there are, say 1000 objects returned by that query, do you really want all of them to reside in application context? Or maybe should they be of "prototype" scope?
As you see, it doesn't play nice with spring concepts. I think the reason for it is that Hibernate and JPA do not "support" an idea of methods inside entities, it's just a different framework. I know there are other frameworks that do allow such a concept, but Hibernate/JPA just doesn't, period
So instead of trying to inject the service into the entity bean, probably you should redesign the application so that the service method will be called from outside, maybe via some facade, and entities will be just populated by query, and then "enriched" with additional information if we're talking about SELECT queries, or, alternatively, some information should be pre-set on entity objects, generated by the Business Logic Layer and only then the entity object should be stored in DB

Spring Data Redis Repository support does not read back embedded complex objects

I have a spring-boot application (1.4RC1, I know it's RC, but Spring Data Redis 1.7.2 is not) where I'm using spring-boot-starter-redis.
The application uses a Spring Data Repository (CrudRepository) which should save an object (using #RedisHash annotation) with String and Boolean properties and one custom class property, which also has only Strings and Longs as properties.
When I save an object (via the repository), everything went fine and I can see all the properties in the database as I would expect.
When I want to read the data from the database (via the repository) I only get the properties from the parent object. The custom class property is null.
I would expect to get the property loaded from the database as well. As the documentation states you can write a custom converter, but since I don't need to do that, when I want to write the data, I shouldn't need to write a reading converter as well.
I wonder if I need to annotate the custom class property, but I couldn't find anything in the documentation. Can you point me in the right direction?
The classes are as follows:
Class sample:
#Data
#EqualsAndHashCode(exclude = {"isActive", "sampleCreated", "sampleConfiguration"})
#RedisHash
public class Sample {
#Id
private String sampleIdentifier;
private Boolean isActive;
private Date sampleCreated;
private SampleConfiguration sampleConfiguration;
public Sample(String sampleIdentifier, SampleConfiguration sampleConfiguration){
this.sampleIdentifier = sampleIdentifier;
this.sampleConfiguration = sampleConfiguration;
}
}
Class SampleConfiguration:
#Data
public class SampleConfiguration {
private String surveyURL;
private Long blockingTime;
private String invitationTitle;
private String invitationText;
private String participateButtonText;
private String doNotParticipateButtonText;
private String optOutButtonText;
private Long frequencyCappingThreshold;
private Long optOutBlockingTime;
}
I added #NoArgsConstructor to my Sample class as Christoph Strobl suggested. Then the repository reads the SampleConfiguration correctly. Thanks, Christoph!

spring data rest hateoas dynamically hide repository

I'm still trying to figure what exactly it is I am asking but this is fallout from a discussion in the office. So the dilemma is that on a mapping set to eager with a repository defined for the entity the mapping is to, a link is produced. Some of the time that is fine but some of the time I'd rather have the object fetched itself. If there is not a repository defined for that entity then that is what will occur with the eager fetch strategy. What would be ideal is if I could pass in a parameter and have the existence of that repository disappear or reappear.
Not totally following, but either the repo exists or not. If you want to be able to access entities of type X independently of other entity types, then you have to define a repo for type X.
I think you could achieve something similar using projections.
So you define define a repository for your association entity. By default spring data rest will just render a link to this entity and not embed it in the response.
Then you define a projection with a getter for your associated entity. You can choose on the client side if you want the projection by adding the projection query parameter.
So lets say you have a person with an address - an exported repository exists for Person and Address:
#Entity
public class Person {
#Id #GeneratedValue
private Long id;
private String firstName, lastName;
#OneToOne
private Address address;
…
}
interface PersonRepository extends CrudRepository<Person, Long> {}
interface AddressRepository extends CrudRepository<Address, Long> {}
Your projection could look like this:
#Projection(name = "inlineAddress", types = { Person.class })
interface InlineAddress {
String getFirstName();
String getLastName();
Address getAddress();
}
And if you call http://localhost/persons/1?projection=inlineAddress you have the address embedded - and by default it is just linked.

Resources