BSON ObjectID (Morphia) representation in Typescript/Angular2 Project - mongodb

I have a Java class representing a customer with some properties like name, adress etc.
And I have the property:
#Id
#Property("_id")
private ObjectId id;
The customer will be fetched from a mongoDB. Everything is fine and all properties are filled.
Then I try to transport data via REST to a angular2 client
I have a Customer representation in typescript
export class Customer {
public id: string <---
Mapping inside rest call in client
.map((response: Response) => <Customer> response.json())
what do I need to put here, that the property will be mapped and that I can use it within the angular client.
I've tried to install bson-objectid via npm, but I have no idea how to get it to map the id property. All the others are working fine.

Solution found!
Create a
public YourAdapterName extends XMLAdapter<String, ObjectID> {
#Override
public String marshal(ObjectId v) throws Exception {
return v.toString();
}
#Override
public ObjectId unmarshal(String v) throws Exception {
return new ObjectId(v);
}
}
This Adapter returns the string representation of the ObjectID and I can use
id: string
in Typescript.

Related

REST Api Spring boot with mongodb how to get json?

#GetMapping("/getAccount")
public Account validateAccount(#RequestBody) {
}
Very new to spring boot. My account file has 5+ values all strings, username, password, id, and some etc things.
Given this
{
"username": "bob"
"password": "password"
}
It should give this with 200 response code OK
{
"id": "45645646546"
"username": "bob"
"password": "password"
"status": "Single"
"filler": "filler"
}
However I'm not sure how to read the "username" and "password" json in my validateAccount function
Not really related to this question but does anyone know how to send a response code in the function? Like .sendresponseheader(400) something like that
public class AccountDTO {
#JsonIgnore
private Long id;
#NotNull
private String username;
#NotNull
private String password;
#JsonIgnore
private String status;
#JsonIgnore
private String filler;
// getters & setters
}
You may want to create a DTO (Data Transaction Object) as shown above. Here's a link to it's wiki.
Next pass map user input into this DTO using #RequestBody annotation.
#RestController
public class AccountController {
#GetMapping("/accounts")
public ResponseEntity<Account> validateAccount(#RequestBody AccountDTO accountDTO) {
return new ResponseEntity<>(accountService.validate(accountDTO), HttpStatus.OK);
}
}
Or you can use
#RestController
public class AccountController {
#GetMapping("/accounts")
public Response validateAccount(#RequestBody AccountDTO accountDTO) {
return new ResponseEntity().ok(accountService.validate(accountDTO));
}
}
The user input will be converted from json to AccountDTO using whatever JSON processor your're using most probably it'll be com.fasterxml.jackson.core.
The #JsonIgnore and #NotNull annotation will ensure only username and password fields are used and others are ignored while taking input from user.
You can pass this DTO to your service classes and use something like findByUsername() in your Business Logic and return populated AccountDTO using the below mapper function or some external libraries like Model Mapper or MapStruct.
public toAccountDTO(Account account) {
AccountDTO accountDTO = new AccountDTO();
accountDTO.setUsername(account.getUsername());
// and so on...
return accountDTO;
}
And for your last query, wrap the returned AccountDTO object in ResponseEntity wrapper to provide a proper Response Code with your payload. Here's a link to ResponseEntity Java docs.
AccountDto.java
===============
class AccountDto{
private Long id;
private String username;
private String password;
private String status;
private String filler;
//getters & setters
}
#GetMapping("/getAccount")
public ResponseEntity validateAccount(#RequestBody AccountDto accountDto) {
return new ResponseEntity<>(accountServie.validate(accountDto),HttpStatus.OK);
}
You can do your custom operations before returning the response. Take a look Best Practice of REST
For json response nothing specific just mark class with #RestController.
For #RequestBody just use a pojo to bind the values
For error code and status you can use ResponseEntity

(JDBI/Dropwizard) PSQLException when retrieving auto-incremented id from PostgreSQL

I'm trying to set up a dropwizard project but I'm stuck. When I try to get the auto generated id field with #GetGeneratedKeys then I'm getting the following Exception:
org.postgresql.util.PSQLException: Bad value for type long : foo.
The request is a simple JSON Request
{"name":"foo"}
The INSERT into the database is successful but it seems that the statement returns the value of the name instead of the generated id. How can I solve this?
I use postgresql, and the table project contains a primary key field "id" with nextval('project_id_seq'::regclass). Here are the POJO, DAO and Resource Classes I use:
public class Project {
private long id;
private String name;
public Project() { // Jackson deserialization }
public Project(long id, String name) {
this.id = id;
this.name = name;
}
...
}
#RegisterMapper(ProjectMapper.class)
public interface ProjectDAO {
#SqlUpdate("insert into project (name) values (:name)")
#GetGeneratedKeys
public long insert(#Bind("name") String name);
}
#Path("/project")
#Consumes({MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_JSON})
public class ProjectResource {
ProjectDAO projectDAO;
public ProjectResource(ProjectDAO personDAO) {
this.projectDAO = personDAO;
}
#POST
#Timed
public Response add(#Valid Project project) {
long newId = projectDAO.insert(project.getName());
project.setId(newId);
return Response.status(Response.Status.CREATED)
.entity(project).build();
}
}
===============
UPDATE
I just figured out that this relates to the fact that my id column isn't the first column in my table. The column name is. The problem occurs because #GetGeneratedKeys is using org.skife.jdbi.v2.sqlobject.FigureItOutResultSetMapper which is using org.skife.jdbi.v2.PrimitivesMapperFactory which returns org.skife.jdbi.v2.util.LongMapper.FIRST. This mapper is calling
java.sql.ResultSet.getLong(1) through the method extractByIndex(...) to retrieve the generated id, which isn't the id in my case...
I'll fix the issue by reorganizing the columns in the database, but I'd like to have a robust implementation if possible: Is there a way to specify the column name of the id column when using the #GetGeneratedKeys Annotation? (The org.skife.jdbi.v2.util.LongMapper class contains a also method called extractByName(...))
This is an issue in the jdbi implementation and is fixed in a newer version as described in https://github.com/jdbi/jdbi/issues/114

Spring boot REST application

I am trying to make a RESTful application in Java using Spring boot by following the tutorial here. I want to modify it so that I can extract an identifier from the URL and use it to serve requests.
So http://localhost:8080/members/<memberId> should serve me a JSON object with information about the member whose ID is <memberId>. I don't know how to
Map all http://localhost:8080/members/* to a single controller.
Extract the from the URL.
Should the logic of extracting the memberId and using it be part of the controller or a separate class, as per the MVC architecture?
I am new to Spring/Spring-boot/MVC. It is quite confusing to get started with. So please bear with my newbie questions.
Map all http://localhost:8080/members/* to a single controller.
You can use a placeholder in a request mapping to so it'll handle multiple URLs. For example:
#RequestMapping("/members/{id}")
Extract the id from the URL
You can have the value of a placeholder injected into your controller method using the #PathVariable annotation with a value that matches the name of the placeholder, "id" in this case:
#RequestMapping("/members/{id}")
public Member getMember(#PathVariable("id") long id) {
// Look up and return the member with the matching id
}
Should the logic of extracting the memberId and using it be part of the controller or a separate class, as per the MVC architecture?
You should let Spring MVC extract the member id from the URL as shown above. As for using it, you'll probably pass the URL to some sort of repository or service class that offers a findById method.
As you can see in the code below, service for customer are in one controller to get one and to add new customer.
So, you will have 2 services:
http://localhost:8080/customer/
http://localhost:8080/customer/{id}
#RestController("customer")
public class SampleController {
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public Customer greetings(#PathVariable("id") Long id) {
Customer customer = new Customer();
customer.setName("Eddu");
customer.setLastname("Melendez");
return customer;
}
#RequestMapping(value = "/{id}", method = RequestMethod.POST)
public void add(#RequestBody Customer customer) {
}
class Customer implements Serializable {
private String name;
private String lastname;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getLastname() {
return lastname;
}
}
}

javaee 6 rest api named query result

I have a simple JEE6 rest class that gets the data from db2. I am using Jackson in ApplicationConfig class to convert the entity objects to json. It converts with the field names as the key and the value as the right hand value. So for example:
Class Entity {
String name;
String address;
}
converts to
{name:"hello", address:"world"}
The service is as follows:
public List<T> findAll() {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
return getEntityManager().createQuery(cq).getResultList();
}
Now I want to only return the name in json format. So I created a named query as follows in the entity class:
#NamedQuery(name = "justGetName", query = "SELECT a.name FROM Applications a")
And the service changed to
public List<T> findAll() {
return getEntityManager().createNamedQuery("justGetName").getResultList();
}
This returns the following array:
[{"first","second","third"}]
But I want to get back:
[{name:"first",name:"second",name:"third"}]
How do I write the named query so that the class field names are added to the json structure? Thank you.
You querying a list of strings from your database and this is what the service returns.
Their are multiple ways to achieve your goal.
Pure JPA
Using #JsonIgnore to tell Jackson not to serialize an attribute
class Application {
String name;
#JsonIgnore
String address;
}
Create a new Entity class that only contains the attributes you would like to share
class ApplicationName {
String name;
}
Alternatively you could introduce a separate class that only contains the attributes you would like to share and convert the results from the query into this class and return than the list of this converted values.

Using the $in operator through Morphia - doing it wrong?

I have the following Play Framework entity (using Morphia for persistence) as part of a generic blogging app:
#Entity
public class Comment extends Model {
...
#Reference
#Indexed
public SiteUser commenter;
public static List<Comment> getLastCommentsByUsers(final List<SiteUser> users) {
final Query<Comment> query ds().createQuery(Comment.class);
query.field(commenter).hasAnyOf(users);
return query.asList();
}
}
SiteUser:
#Entity(noClassnameStored=true)
public class SiteUser extends AbstractUser {
public String realName;
}
AbstractUser:
public class AbstractUser extends Model {
#Indexed(value= IndexDirection.DESC, unique = true)
public String emailAddress;
#Required
public String password;
}
The method getLastCommentsByUsers() is supposed to return all comments by the users in the users parameter, but I always get an empty List back. The reason that Commment is a separate collection is to be able to retrieve last X Comments by certain users across their associated Posts, which isn't possible if the Comment is embedded in the Post collection.
Is there something wrong with my query (should I be using something other than hasAnyOf), or is it a problem with the relationship mapping - should I be using ObjectId instead?
I use the in() method with a list or set and its working perfectly. Here's a snippet:
List<String> keywordList;
List<Product> products = Product.find().field("keywords").in(keywordList).asList();
This should work for collection of embedded or references too.
You should use List<Key<SiteUser>> to query:
public static List<Comment> getLastCommentsByUsers(final List<SiteUser> users) {
final Query<Comment> query ds().createQuery(Comment.class);
query.field(commenter).hasAnyOf(toKeys(users)); // convert to keys
return query.asList();
}
public static List<Key<SiteUser>> toKeys(List<SiteUser> users) {
List<Key<SiteUser>> keys = new ArrayList<Key<SiteUser>>();
for(SiteUser user: users) {
keys.add(ds().getMapper().getKey(user));
}
return keys;
}
Or you can just get the keys by:
List<Key<SiteUser>> keys = ds().createQuery(SiteUser.class).query().filter(...).asKeyList();