I have implemented a basic mvc app using Spring, i annotated my class as follows
I have added Spring oxm to my pom, but not added jaxb or json handlers.
My configuration is pretty much empty.
So my question is how is spring producing xml output when i call a GET in my controller and returning the following object in xml.
Where is it finding the xml marshaller, is it in the spring-oxm? is there default?
Is this the httpmessageconverters? i set my controller tot he following:
#RequestMapping(value= "/state", method = RequestMethod.GET, produces={MediaType.TEXT_XML_VALUE })
public ResponseEntity<GameState> getGameState(.. response,... request) {..}
my object :
#XmlRootElement(name = "door")
public class GameState {
private int id;
private String state;
public GameState() {
super();
}
public GameState(int id, String state) {
this.id = id;
this.state = state;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
Java 6 has JAXB built into the distro, you are specifying the container that ur looking by the
#XmlRootElement(name = "door")
If you will need more information on JAXB bundling here is the API documentation .
Related
I am reading and learning Spring Boot data with MongoDB. I have about 10 records in my database in the following format:
{
"_id" : ObjectId("5910c7fed6df5322243c36cd"),
name: "car"
}
When I open the url:
http://localhost:8090/items
I get an exhaustive list of all items. However, I want to use the methods of MongoRepository such as findById, count etc. When I use them as such:
http://localhost:8090/items/count
http://localhost:8090/items/findById/5910c7fed6df5322243c36cd
http://localhost:8090/items/findById?id=5910c7fed6df5322243c36cd
I get a 404.
My setup is as so:
#SpringBootApplication
public class Application {
public static void main(String[] args) throws IOException {
SpringApplication.run(Application.class, args);
}
}
#Document
public class Item implements Serializable {
private static final long serialVersionUID = -4343106526681673638L;
#Id
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
#RepositoryRestResource(collectionResourceRel = "item", path = "items")
public interface ItemRepository<T, ID extends Serializable> extends MongoRepository<Item, String>, ItemRepositoryCustom {
}
What am I doing wrong? Do I need to implement the methods as defined by MongoRepository or will they be automatically implemented? I am lost and have been trying to figure this out for so long. I do not have any methods in my controller, its empty.
You have to declare the findById method in order for it to be exposed.
Item findById(String id);
Item findByName(String name);
Note that you don't need to implement the methods. SpringBoot will analyse the method name and provide the proper implementation
I had same issue,
After removing #Configuration,#ComponentScan everything worked fine.
I have a simple WebSocket set up and try to save data. Somehow the data gets not persisted. I don't get any error messages and the object gets returned correct to the client. If I try to store the object with a REST controller and a REST request it works.
Here are the dependencies of my build.gradle file:
dependencies {
compile 'org.springframework.boot:spring-boot-starter-web'
compile 'org.springframework.boot:spring-boot-starter-data-jpa'
compile 'org.springframework.boot:spring-boot-starter-websocket'
compile 'org.springframework:spring-messaging'
compile 'com.google.code.gson:gson:1.7.2'
compile 'org.postgresql:postgresql:9.4-1200-jdbc41'
compile 'commons-dbcp:commons-dbcp:1.4'
testCompile('org.springframework.boot:spring-boot-startet-test')
}
PersonController
#Controller
public class PersonController {
#Autowired
PersonRepository personRepository;
#MessageMapping("/test")
#SendTo("/response/test")
public Person test() throws Exception {
Person person = new Person();
person.setName("John Doe");
return personRepository.save(person);
}
}
Configuration for STOMP messaging
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/response");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/websocket")
.setAllowedOrigins("*")
.withSockJS();
}
Person entity
#Entity
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return getName;
}
public void setName(String name) {
this.name = name;
}
}
Base Repository
#NoRepositoryBean
public interface BaseRepository<T, ID extends Serializable> extends Repository<T, ID> {
void delete(T deleted);
void delete(ID id);
Iterable<T> findAll();
T findOne(ID id);
T save(T persisted);
Iterable<T> save(Iterable<T> persited);
}
Person Repository
public interface PersonRepository extends
BaseRepository<Person, Serializable> {
}
Is there a problem in my code?
Is there an issue with caching? Do I have to force flushing?
Is storing data with WebSockets supported by SpringBoot?
Do you know any examples with storing data? I could only find basic examples without storing data.
The problem was in my persistence configuration. I changed the configuration from a Java implementation to the application.properties file. I think there was a problem with my transaction manager.
To be complete, here is my current application.properties file:
spring.datasource.url = jdbc:postgresql://localhost:5432/test
spring.datasource.username = test
spring.datasource.password = test
spring.datasource.testWhileIdle = true
spring.datasource.validationQuery = SELECT 1
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto = create
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
I am still somewhat of a novice with Spring Boot and Spring Data Rest and hope someone out there with experience in Accessing by Property. Since I cannot change a database which stores types for Letters in an unnormalized fashion (delimited string in a varchar), I thought that I could leverage some logic in properties to overcome this. However I notice that when using property access, some of my getters are never called.
My Model code:
package ...
import ...
#Entity
#Table(name="letters", catalog="clovisdb")
#Access(AccessType.PROPERTY)
public class Letter {
public enum PhoneticType {
VOWEL, SHORT, LONG, COMMON;
public static boolean contains(String s) { ... }
}
public enum PositionType {
ALL, INITIAL, MEDIAL, FINAL;
public static boolean contains(String s) { ... }
}
public enum CaseType {
ALL, LOWER, UPPER;
public static boolean contains(String s) { ... }
}
private int id;
private String name;
private String translit;
private String present;
private List<PhoneticType> phoneticTypes;
private CaseType caseType;
private PositionType positionType;
#Id
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getTranslit() { return translit; }
public void setTranslit(String translit) { this.translit = translit; }
public String getPresent() { return present; }
public void setPresent(String present) { this.present = present; }
public String getTypes() {
StringBuilder sb = new StringBuilder(); //
if (phoneticTypes!=null) for (PhoneticType type : phoneticTypes) sb.append(" ").append(type.name());
if (caseType!=null) sb.append(" ").append(caseType.name());
if (positionType!=null) sb.append(" ").append(positionType.name());
return sb.substring( sb.length()>0?1:0 );
}
public void setTypes(String types) {
List<PhoneticType> phoneticTypes = new ArrayList<PhoneticType>();
CaseType caseType = null;
PositionType positionType = null;
for (String val : Arrays.asList(types.split(" "))) {
String canonicalVal = val.toUpperCase();
if (PhoneticType.contains(canonicalVal)) phoneticTypes.add(PhoneticType.valueOf(canonicalVal));
else if (CaseType.contains(canonicalVal)) caseType = CaseType.valueOf(canonicalVal);
else if (PositionType.contains(canonicalVal)) positionType = PositionType.valueOf(canonicalVal);
}
this.phoneticTypes = phoneticTypes;
this.caseType = (caseType==null)? CaseType.ALL : caseType;
this.positionType = (positionType==null)? PositionType.ALL : positionType;
}
#Override
public String toString() { .... }
}
My Repository/DAO code:
package ...
import ...
#RepositoryRestResource
public interface LetterRepository extends CrudRepository<Letter, Integer> {
List<Letter> findByTypesLike(#Param("types") String types);
}
Hitting this URI: http://mytestserver.com:8080/greekLetters/6
and setting breakpoints on all the getters and setters, I can see that the properties are called in this order:
setId
setName
setPresent
setTranslit
setTypes
(getId not called)
getName
getTranslit
getPresent
(getTypes not called !!)
The json returned for the URI above reflects all the getters called, and there are no errors
{
"name" : "alpha",
"translit" : "`A/",
"present" : "Ἄ",
"_links" : {
"self" : {
"href" : "http://mytestserver.com:8080/letters/6"
}
}
}
But why is my getTypes() not being called and my JSON object missing the “types” attribute? I note that the setter is called, which makes it even stranger to me.
Any help would be appreciated!
Thanks in advance
That's probably because you don't have a field types, so getTypes() isn't a proper getter. Try adding this to your entity
#Transient
private String types;
I don't know how the inner works, but it's possible that the class is first scanned for its fields, and then a getter is called for each field. And since you don't have types field, the getter isn't called. Setter getting called could be a feature but I wouldn't be surprised if it is a bug, because findByTypesLike should translate to find Letters whose types field is like <parameter>, and types is not a field.
Another thing you can try, is to annotate that getter with #JsonInclude. Jackson 2 annotations are supported in Spring versions 3.2+ (also backported to 3.1.2).
I am having issues with RPC calls and GWT. Essentially, I have a Person class (common code between client and server) that is created in the client side web code, sent to the server code via an RPC call, and then saved to a DB (OrientDB). I have verified that the following work:
RPC call - I am able to send info to the server and retrieve info from the server
save to DB - have verified that a Person object is saved to the DB
Where I am having issues is the transfer of the POJO from the client to the server. I have verified that the POJO's properties are intact right before it is sent to the server, however, the object passed to the server contains null values for all properties. Essentially, the class is transferred but the information is not. It then saves to the DB, but obviously without any relevant information contained within it.
I will copy what I feel is relevant below, please let me know what else I can provide to make this problem easier to identify. Note these are still in a testing state, so mind the comments :)
Any idea why my POJO's information is being lost in translation?
Person object, followed by the abstract class it inherits from:
public class Person extends org.matesweb.shared.AbsPerson implements Serializable
{
#Id
private String id; // DON'T CREATE GETTER/SETTER FOR IT TO PREVENT THE CHANGING BY THE USER APPLICATION,
// UNLESS IT'S NEEDED
//sets new user details
public void setPerson(String fIrstName, String mIdInit, String lAstName, String email, String password)
{
firstName = fIrstName;
middleInitial = mIdInit;
lastName = lAstName;
}
/*getter and setter methods - required for every
* field due to restrictions imposed by OrientDB*/
public Object getId()
{
String tmp;
tmp = id.toString();
return tmp;
}
//end class
}
public class AbsPerson implements Serializable
{
String firstName;
String middleInitial;
String lastName;
// public sys.Login login;
public org.matesweb.shared.Group[] groups;
private org.matesweb.shared.Purchase[] purchases;
/*this method adds a new purchase to the purchases variable*/
/* public void addPurchase(float price, String description)
{
people.Purchase newPurchase = new people.Purchase(login, price, description);
}
*/
/*adds a person to a group by comparing the passed in group ID and PWD*/
public void addGroup(String groupID, String groupPWD)
{
//compare group ID with group PWD to add a user to the group
}
/*getter and setter methods - required for every
* field due to restrictions imposed by OrientDB*/
public String getFirstName()
{
return firstName;
}
public void setFirstName(String name)
{
firstName = name;
}
public String getMiddleInitial()
{
return middleInitial;
}
public void setMiddleInitial(String midInit)
{
middleInitial = midInit;
}
public String getLastName()
{
return lastName;
}
public void setLastName(String ln)
{
lastName = ln;
}
/*
public sys.Login getLogin()
{
return login;
}
public void setLogin(sys.Login log)
{
login = log;
}
*/
public org.matesweb.shared.Group[] getGroups()
{
return groups;
}
public void setGroups(org.matesweb.shared.Group[] gro)
{
groups = gro;
}
public org.matesweb.shared.Purchase[] getPurchases()
{
return purchases;
}
public void setPurchases(org.matesweb.shared.Purchase[] purch)
{
purchases = purch;
}
}
Service
package org.matesweb.client;
import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
import org.matesweb.shared.Person;
#RemoteServiceRelativePath("peopleService")
public interface PeopleService extends RemoteService {
//test services
String stringTest(String outgoingString);
Person getPerson(String persId);
//production services
String savePerson(Person p);
}
ServiceAsync
import com.google.gwt.user.client.rpc.AsyncCallback;
import org.matesweb.shared.Person;
public interface PeopleServiceAsync
{
//tests
void stringTest(String outgoingString, AsyncCallback<String> incomingString);
void getPerson(String persId, AsyncCallback<Person> retPerson);
//production services
void savePerson(Person p , AsyncCallback<String> st);
}
ServiceImpl call for this particular method:
//production calls
#Override
public String savePerson(Person p) {
String st = ioObj.saveObj(p);
if(st.equals("Success")){
return "Your information has been saved successfully!";
} else{
return "Something has gone wrong on our end... Sorry! Error:<br /> " + st;
}
}
and finally, the call itself
private static void savePerson(Person p)
{
// Initialize the service proxy.
if (peopleSvc == null) {
peopleSvc = GWT.create(PeopleService.class);
}
//resets status
st="";
// Set up the callback object.
AsyncCallback<String> callback = new AsyncCallback<String>() {
#Override
public void onFailure(Throwable caught) {
st = caught.getMessage();
Label stLabel= new Label(st);
personTable.setWidget(3,1,stLabel);
}
#Override
public void onSuccess(String result) {
st = result;
HTML stLabel= new HTML(st);
joinPanel.add(stLabel);
}
};
// Make the call to the people service.
peopleSvc.savePerson(p, callback);
}
I was able to fix this issue by implementing GWT's IsSerializable interface. I also removed the Serializable interface from the Person class and let it inherit IsSerializable from the abstract class it inherits from.
I have inherited some struts2 REST-plugin based code, and the following construct puzzles me:
#Namespace("/merchants/{id}")
public class MerchantAction extends ActionSupport implements ModelDriven<Object> {
private Merchant merchant = new Merchant(); // A Model
private Iterable<Merchant> merchants; // A list of models
....
public HttpHeaders index() {
merchants = merchantService.findAllMerchants();
return new DefaultHttpHeaders("index");
}
#Override
public Object getModel() {
return (merchant != null ? merchant : merchants);
}
public void setId(String id) {
merchant = merchantService.findMerchant(id));
}
In other words, it seems to be toggling between returning a list and returning an individual item in the getModel() call. Is this kosher ? Looks a bit strange to me
I've considered your approach, but finally gave it up. IMO, it lost the advantage of strong typed action.
My solution is, creating a ViewModel for each action. In the view models, there can be the single model, the list of the model, and other items for pages usage, such as items for drop down list or radio buttons.
So the UserViewModel is like:
public class UserViewModel implements IViewModel<User> {
private User model;
private List<User> list;
public void setModel(User user) {
this.model = user;
}
public User getModel() {
return model;
}
public void setList(List<User> list) {
this.list = list;
}
public List<User> getList() {
return list;
}
}
And the actions are like:
public class UserController implements ModelDriven<UserViewModel> {
private int id;
private UserViewModel model = new UserViewModel();
public String index() {
return "success";
}
public String show() {
return "success";
}
public void setId(int id) {
this.id = id;
}
public int getId() {
return this.id;
}
#Override
public UserViewModel getModel() {
return model;
}
}
But in this way, I still lose the shortcut way in jsp files. I should write long model.userName instead of short userName.
I'm still finding the best solution of it.