JAX RS get list of objects - java

Trying to play with JAX RS i want to implement CRUD operations with my data. First of all i want to get list of objects in json formate.
#Path("/users")
public class ListUsersRestController {
#GET
#Produces("application/json")
public List<User> getUsers(){
List<User> users = new ArrayList<>();
users.add(new User("Dean", "Winchester"));
users.add(new User("Sam", "Winchester"));
users.add(new User("Bobby", "Singer"));
return users;
}
#XmlRootElement
public class User {
#XmlElement(name="first-name")
private String firstName;
#XmlElement(name="last-name")
private String lastName;
public User(){
}
public User(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
}
When i request my URI i always get 500 server error and there are no any errors in log file (I am using glassfish).

The problem is here:
#XmlRootElement
public class User {
...
}
Your User class now is an inner class of ListUsersRestController and it seems that JAXB fails to marshall inner classes (because they are more like an instance member of ListUsersRestController than a real class). Either externalize it to be a normal class or make it static:
#XmlRootElement
public static class User {
...
}

Related

In which cases does JpaRepository automatically create the query without you having to use #Query annotation

I am following a Udemy tutorial in Spring boot. There's a part where #Query wasn't used for a user-created method in the repository interface. It works, but I want to understand when JpaRepository takes care of the creation of query. In the User class below, #Table wasn't used.
findByEmail(String email) method works without any implementation/definition. So, my impression was that, JpaRepository automatically created the Select from User where email = emailargument
So here's what I have
A database named reservation with table User
application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/reservation
spring.datasource.username=root
User.java
import javax.persistence.Entity;
#Entity
public class User extends AbstractEntity{
private String firstName;
private String lastName;
private String email;
private String password;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
UserRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
import com.project.flightreservation.entities.User;
public interface UserRepository extends JpaRepository<User, Long> {
User findByEmail(String email);
}
When Spring Data creates a new Repository implementation, it analyses all the methods defined by the interfaces and tries to automatically generate queries from the method names. While this has some limitations, it's a very powerful and elegant way of defining new custom access methods with very little effort. Ref
by implementing one of the Repository interfaces, the DAO will already have some basic CRUD methods (and queries) defined and implemented.
You can create more complex queries with this approach reference
The one which you posted in question is called automatic custom query.
JPA has ability to construct query in different ways. You can use queries derived from methodName with the predicates IsStartingWith, StartingWith, StartsWith, IsEndingWith, EndingWith, EndsWith, IsNotContaining, NotContaining, NotContains, IsContaining, Containing, Contains the respective arguments for these queries will get sanitized.
If you face the situation in which either the method name parser does not support the keyword you want to use or the method name would get unnecessarily ugly, you can use #Query for namedQuery support of JPQL or nativeQuery.
I would strongly suggest you to go through this documentation

Choosing what pojo to use based on the user role on an edit request

So I am wondering what the best way to process an edit request based on a user role.
Say I have the following PostMapping:
#PostMapping(value = "/edit")
public ResponseEntity<String> editIoc(#RequestBody GeneralPojoAllFields editRequest)
the GeneralPojoAllFields looks like this:
public class GeneralPojoAllFields {
private String firstName;
private String lastName;
private String onlyAdminCanEditField;
}
This is the pojo the the admin will be able to use and that will eventually get mapped into the entity class to be saved to the database. However, if we have a regular user who wants to edit it and hypothetically they aren't restricted in the UI would that design work? What I am currently thinking is I would have a user pojo like so:
public class UserPojo {
private String firstName;
private String lastName;
}
After the request mapping comes we check if the user is either regular user or an admin. If it is a regular user we just map the GeneralPojoAllFields to the UserPojo and it wont map over the onlyAdminCanEditField and continue from there.
Is there a better way to do this?
First, your backend should be as independent of the UI as possible. So, access control in UI is a good to have design, but you should not depend upon it.
Now, coming back to your question, yes you can use SecurityContextHolder to find out if the user if regular user/admin. However, if its possible, I would suggest making two controllers, one for admin and one for regular user. Use #PreAuthorize on the admin controller to restrict access. Having two separate controllers will increase readability of your code tremendously.
Additionally, you can call the same service class method from both the controllers. And since you already have two POJO classes, you can use them in #RequestBody and let Spring take care of the mappings for you.
Well, it depends what you think a better way would be. It also depends a bit on your data source. But as there is no information on that here, I would suggest that a better way to do yours is by inheritance.
Make UserPojo the super class and GeneralPojoAllFields extend that class.
UserPojo.java:
public class UserPojo {
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public UserPojo() {}
public UserPojo(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
GeneralPojoAllFields.java:
public class GeneralPojoAllFields extends UserPojo {
private String onlyAdminCanEditField;
public String getOnlyAdminCanEditField() {
return onlyAdminCanEditField;
}
public void setOnlyAdminCanEditField(String onlyAdminCanEditField) {
this.onlyAdminCanEditField = onlyAdminCanEditField;
}
public GeneralPojoAllFields() {}
public GeneralPojoAllFields(String firstName, String lastName, String onlyAdminCanEditField) {
super(firstName, lastName);
this.onlyAdminCanEditField = onlyAdminCanEditField;
}
}
App.java:
public class App {
public static void main(String[] args) {
UserPojo up1 = new UserPojo();
up1.setFirstName("MyFirstName");
up1.setLastName("MyLastName");
GeneralPojoAllFields gpaf1 = new GeneralPojoAllFields();
gpaf1.setFirstName("MyFirstName");
gpaf1.setLastName("MyLastName");
gpaf1.setOnlyAdminCanEditField("yes");
}
}

Room #Query error: Cannot find method parameters

in my project I have a library module and an application module using it. In both modules I have the same gradle dependencies on Android Architecture Components library:
// ViewModel and LiveData
implementation "android.arch.lifecycle:extensions:1.0.0"
implementation "android.arch.lifecycle:common-java8:1.0.0"
// Room
implementation "android.arch.persistence.room:runtime:1.0.0"
annotationProcessor "android.arch.persistence.room:compiler:1.0.0"
In my library module I have defined a User entity
#Entity(tableName = "users",
indices = {#Index(value = {"firstName", "lastName"})})
public class User {
public enum ROLE {
...
}
public enum FEEDBACK_LEVEL {
...
}
#PrimaryKey
public int id;
#TypeConverters(UserConverters.class)
ROLE role;
#TypeConverters(UserConverters.class)
FEEDBACK_LEVEL feedbackLevel;
public String firstName;
public String lastName;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public ROLE getRole() {
return role;
}
public void setRole(ROLE role) {
this.role = role;
}
public FEEDBACK_LEVEL getFeedbackLevel() {
return feedbackLevel;
}
public void setFeedbackLevel(FEEDBACK_LEVEL feedbackLevel) {
this.feedbackLevel = feedbackLevel;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
and the related DAO interface
#Dao
public interface UserDAO {
#Insert(onConflict = OnConflictStrategy.REPLACE)
void insertUser(User ... u);
#Query("select * from users where users.id = :userId")
LiveData<User> getUser(int userId);
}
In my application module I've created my database in which I'm using the entity defined in the library project
#Database(entities = {User.class}, version = 1)
public abstract class TDatabase extends RoomDatabase{
private static TDatabase sInstance;
public static TDatabase getInstance(final Context c) {
if(sInstance == null)
sInstance = Room.databaseBuilder(c, TDatabase.class, "t_db").build();
return sInstance;
}
public abstract UserDAO userDao();
}
The problem is that when I try to refer to a method parameter in a #Querystatement using its name I get the following error
Error:Each bind variable in the query must have a matching method parameter. Cannot find method parameters for :userId.
If I change the #Query from
#Query("select * from users where users.id = :userId")
LiveData<User> getUser(int userId);
to
#Query("select * from users where users.id = :arg0")
LiveData<User> getUser(int userId);
everything works fine.
Am I doing some mistakes? Why I'm getting this error?
I've googled for a solution but I found only results referring to Kotlin while I'm using Java.
This issue reported at https://issuetracker.google.com/issues/68118746 and fixed in version 1.1.0-alpha3, but only for Kotlin code since parameter names are always stored in Kotlin classes metadata.
For Java, there is only workaround with :arg0 until annotation like NamedArg will be added to Room.
I think you should use it like that:
#Query("select * from users where id = (:userId)")
LiveData<User> getUser(int userId);
This problem still pops up for me sometimes when working on db logic, but "Clean Project" usually fixes it in IntelliJ IDEA (should work just the same in Android Studio).

How to use mongodb embedded schema in java

I am stuck here, i want to keep address of user as embedded document . But there,it is creating another table of address in database. so i want one table "user" and inside it,i want my embedded document like "address". what will be the domain design of user ?.
Now,my user domain is
class User{
String name;
Address adress;
}
My address domain is
class Address{
String city;
}
My controller is
#RestController
#RequestMapping("/api/v1")
public class UserController {
public Map<String, Object> saveUser(#RequestBody User user) {
userService.saveUser(user);
return ResponseHandler.generateResponse("User registerted successfully", HttpStatus.ACCEPTED, false, null);
}
}
My service is
public void saveUser(User user){
Address a = new Address();
a.setCity("delhi");
User user = new User();
user.setAddress(a);
userDao.save(user);
}
I want result is in database,not table of address separately.i am using spring-data-mongotemplate for this.how can i do this ?
user{
address:[{},{}] // multiple address could be
}
Maybe something like this?
#Document
public class User {
private String name;
private List<Address> addresses = new ArrayList<>();
// ctr, getters, setters...
public static class Address {
private String city;
public Address(String city) {
this.city = city;
}
// getters, setters...
}
}
In controller:
User.Address address = new User.Address("NY");
user.setAddress(address);
mongoTemplate.save(user);
Basically, parsing User from json should work:
{ name : "userName", addresses : [ { city : 'NY' } ] }
And you don't have to embed Address class into User class. Just add #Document on User and ebmed Address object in it.
Use #Document annotation in user, and both must implements Serializable.
Regards.

How to create DTO class

I want to create DTO class for User. my input to program is
firstname, lastname,lastname.role,group1,group2,group3.
so for each user role consist of group_1,group_2,group_3.....
In database i want to store in following format
demo,demo,demo,roleId, gorup_1_name group_1_Id
demo,demo,demo,roleId, gorup_2 and group_2_Id
demo,demo,demo,roleId, gorup_3 and group_3_Id
I was able separate all this things , but i want to assign this value to userDTO class and stored into database. basically im new to core java part. so how can create structure for this?
A Data Transfer Object (DTO) class is a java-bean like artifact that holds the data that you want to share between layer in your SW architecture.
For your usecase, it should look more or less like this:
public class UserDTO {
String firstName;
String lastName;
List<String> groups;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public List<String> getGroups() {
return groups;
}
public void setGroups(List<String> groups) {
this.groups = groups;
}
// Depending on your needs, you could opt for finer-grained access to the group list
}
One thing to add:
The essence of a DTO is that it transfers data across the wire. So it will need to be Serializable.
http://martinfowler.com/eaaCatalog/dataTransferObject.html

Categories

Resources