Filter nested objects using Jackson's BeanPropertyFilter - jackson

I have the following objects:
#JsonFilter("myFilter")
public class Person {
private Name name;
private int age;
public Name getName() {return name;}
public void setName(Name name) {this.name = name;}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
}
#JsonFilter("myFilter")
public class Name {
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;}
}
I wrote a method to marshall a Person object like this:
#Test
public void test() throws Exception {
Person person = new Person();
person.setAge(10);
Name name = new Name();
name.setFirstName("fname");
name.setLastName("lastname");
person.setName(name);
ObjectMapper mapper = new ObjectMapper();
FilterProvider filters = new SimpleFilterProvider().addFilter("myFilter",
SimpleBeanPropertyFilter.filterOutAllExcept("name.firstName"));
System.out.println(mapper.filteredWriter(filters).writeValueAsString(person));
}
What I'd like to see is JSON like this:
{"name":{"firstName":"fname"}}
Is something like that possible?

Ok, figured it out. Varargs would have made this a bit prettier, but oh well. Just hope I don't have two inner beans which have properties with the same name. I wouldn't be able to make the distinction between the two
FilterProvider filters = new SimpleFilterProvider()
.addFilter("myFilter", SimpleBeanPropertyFilter
.filterOutAllExcept(new HashSet<String>(Arrays
.asList(new String[] { "name", "firstName" }))));

There's a better way that solves problem with property name conflicts. Just add another filter to class Name ("nameFilter"):
#JsonFilter("personFilter")
public class Person {
private Name name;
private int age;
public Name getName() {return name;}
public void setName(Name name) {this.name = name;}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
}
#JsonFilter("nameFilter")
public class Name {
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;}
}
And then add 2 filters, one for Person and one for Name:
FilterProvider filterProvider = new SimpleFilterProvider()
.addFilter("personFilter", SimpleBeanPropertyFilter.filterOutAllExcept("name"))
.addFilter("nameFilter", SimpleBeanPropertyFilter.filterOutAllExcept("firstName"));

Related

Resteasy - Multiple resource methods match request "POST /.../..."

I am doing a REST API with Java Resteasy framework (using Jackson as well).
I was trying to define 2 api endpoints almost equal:
#POST
#Path("/addbook")
#Produces(MediaType.APPLICATION_XML)
#Consumes(MediaType.APPLICATION_XML)
public BookAdvanced addBook (BookAdvanced book){...}
#POST
#Path("/addbook")
#Produces(MediaType.APPLICATION_XML)
#Consumes(MediaType.APPLICATION_XML)
public Book addBook (Book book){...}
Is this possible? What I want is, depending on the xml arriving execute one or the other method
Here book class:
package package1;
import javax.xml.bind.annotation.*;
import java.util.Date;
#XmlRootElement(name = "book")
public class Book {
private Long id;
private String name;
private String author;
#XmlAttribute
public void setId(Long id) {
this.id = id;
}
#XmlElement(name = "title")
public void setName(String name) {
this.name = name;
}
#XmlElement(name = "author")
public void setAuthor(String author) {
this.author = author;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public String getAuthor() {
return author;
}
// constructor, getters and setters
}
Here BookAdvanced class:
package package1;
import javax.xml.bind.annotation.*;
import java.util.Date;
#XmlRootElement(name = "book")
public class BookAdvanced {
private Long id;
private String name;
private String author;
private int year;
#XmlAttribute
public void setId(Long id) {
this.id = id;
}
#XmlElement(name = "title")
public void setName(String name) {
this.name = name;
}
#XmlElement(name = "author")
public void setAuthor(String author) {
this.author = author;
}
#XmlElement(name = "year")
public void setYear(int year) {
this.year = year;
}
public Long getId() {
return id;
}
public String getName() {
return name;
}
public String getAuthor() {
return author;
}
public int getYear() {
return year;
}
// constructor, getters and setters
}
27-Jan-2023 12:33:18.238 WARN [http-nio-8080-exec-39] org.jboss.resteasy.core.registry.SegmentNode.match RESTEASY002142: Multiple resource methods match request "POST /hello/addbook". Selecting one. Matching methods: [public package1.BookAdvanced prova_gradle_war.HelloWorldResource.addBook(package1.BookAdvanced), public package1.Book prova_gradle_war.HelloWorldResource.addBook(package1.Book)]
Matching is based on the request URI and not the request body. There is no real way to match the path and decide the method to use based on the body.
You could do something manually where you inspect the data and determine which type to create.

Spring RestController ignoring #jsonProperty/JsonGetter/JsonSetter

I am using Springboot 2.1.2.RELEASE. I have a get request with an object as input parameter. Expecting the attributes in my class to be request parameters. My EmployeeBean has properties in java naming convention. But I need the custom names to request parameters. Tried to achieve that using #JsonProperty/ #Jsongetter/ #JsonSetter annotations but its not working. Am I missing something?
#RequestMapping(value="/api", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE )
public List<Map<String, Object>> getEmployeeData(EmployeeBean employeeBean
#Data
public class EmployeeBean implements Serializable {
private static final long serialVersionUID = -2757478480787308113L;
#JsonProperty(value="first_name")
private String firstName;
#JsonProperty(value="last_name")
private String lastName;
Try this,
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;
}
#JsonProperty(value="first_name")
public void setFirst_name(String firstName) {
this.firstName = firstName;
}
#JsonProperty(value="last_name")
public void setLast_name(String lastName) {
this.lastName = lastName;
}
controller
#RestController
public class JsonController {
#RequestMapping(value="/api", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE )
public List<Map<String, Object>> getEmployeeData(EmployeeBean employeeBean) {
System.out.println("employeeBean: "+employeeBean);
return null;
}
}
result:
employeeBean: EmployeeBean [firstName=firstName10, lastName=lastName20]
I've tested and it's worked
other options, using JsonCreator in constructor:
private String firstName;
private String lastName;
#JsonCreator
public EmployeeBean(#JsonProperty("first_name") String first_name, #JsonProperty("last_name") String last_name) {
this.firstName = first_name;
this.lastName = last_name;
}
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;
}

#Indexed annotation is ignored

I have a simple Product class as it follows
#SolrDocument(collection = "product")
public class Product {
#Id
#Indexed(name = "id", type = "string")
private String id;
#Field
#Indexed(name = "namex", type = "text_general", stored = false, searchable=true)
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;
}
}
my problem is that the annotation #Indexed is completely ignored. The name of the field is simply name (instead of namex) and the field is stored. Any guess?
UPDATE 1 if I remove the type annotation name works, but stored has no effect still
I managed by modifying the bean that creates the SolrTemplate object like follows:
#Bean
public SolrTemplate solrTemplate(SolrClient client) throws Exception {
SolrTemplate st = new SolrTemplate(client);
st.setSchemaCreationFeatures(Collections.singletonList(Feature.CREATE_MISSING_FIELDS));
st.afterPropertiesSet();
return st;
}

Are custom classes in Java mutable by default?

I've been reading up on encapsulation and was wondering; if I make a new class, is it by default mutable?
If so, how would I go about making it an immutable class, if possible, without just doing defensive copying?
Thanks.
It depends on what you put in the class.
public class MutableClass {
private String firstName;
public MutableClass(String s) {
firstName = s;
}
public String getFirstName() {
return firstName;
}
// this allows mutation...
public void setFirstName(String s) {
firstName = s;
}
}
public class ImmutableClass {
private String firstName;
public MutableClass(String s) {
firstName = s;
}
public String getFirstName() {
return firstName;
}
}
That doesn't account of things like setAccessible with reflection, but I expect that is not what you are concerned about.
I hope that helps.

Hibernate : #OneToMany : Always deleting and reinserting the child records

Please help me resolve this issue. I tried googling for a solution and couldn't find one for this.
Table structure
Table: Catalog
catalog_id (primary key)
name
Table: Catalog_Locale
catalog_id
locale_id
sequence
composite key(catalog_id,locale_id)
Class
public Class Catalog{
#Id
#Column(name = "CATALOG_ID", nullable = false)
private String catalogId;
#Column(name = "NAME")
private String name;
#OneToMany(targetEntity = CatalogLocale.class,fetch=FetchType.LAZY)
#JoinColumn(name = "CHILD_CATALOG_ID", nullable = false)
#Cascade(value = {})
protected List<CatalogLocale> locales = new ArrayList<CatalogLocale>(10);
public void setCatalogId( String catalogId ){
this.catalogId = catalogId;
}
public void setName( String name ){
this.name = name;
}
public void setLocales( List<CatalogLocale> locales ){
this.locales = locales;
}
public void getCatalogId(){
return catalogId;
}
public void getName(){
return name;
}
public void getLocales(){
return locales;
}
}
public class CatalogLocale{
#EmbeddedId
CatalogLocalePk catalogLocalePk;
#Column(name = "SEQUENCE")
private int sequence;
public void setCatalogLocalePk( CatalogLocalePk catalogLocalePk ){
this.catalogLocalePk = catalogLocalePk;
}
public void setSequence( int sequence ){
this.sequence = sequence;
}
public CatalogLocalePk getCatalogLocalePk(){
return catalogLocalePk;
}
public int getSequence(){
return sequence;
}
#Embeddable
public static class CatalogLocalePk{
#Column(name = "CATALOG_ID", nullable = false)
private String catalogId;
#Column(name = "LOCALE_ID", nullable = false)
private String localeId;
public CatalogLocalePk(){
}
public CatalogLocalePk( String catalogId, String localeId ){
this.catalogId = catalogId;
this.localeId = localeId;
}
public void setCatalogId( String catalogId ){
this.catalogId = catalogId;
}
public void setLocaleId( String localeId ){
this.localeId = localeId;
}
public String getCatalogId(){
return catalogId;
}
public String getLocaleId(){
return localeId;
}
}
}
The code works for fine for the insert operation, but for any update to the Catalog will trigger for delete and reinsert all entries of the child table.
Is there any solution for this?