Order Attribute in JacksonXmlProperty - java

In the below code, I am expecting the attributes in the order of properties defined, but not able to get it. The order is always mixed up.
Parent Tag
#JacksonXmlRootElement
public class ParentSpec{
#JacksonXmlProperty(localName = "parentSpec")
#JacksonXmlElementWrapper
public MySpec mySpec;
}
ChildTag
public class MySpec {
#JacksonXmlProperty(localName = "mySpec")
#JacksonXmlElementWrapper(useWrapping = false)
public List<MyData> myDataList;
}
Error Child
#JsonPropertyOrder({"id", "type", "name", "data"})
public class MyData{
#JacksonXmlProperty(isAttribute = true)
public String id;
#JacksonXmlProperty(isAttribute = true)
public String type;
#JacksonXmlProperty(isAttribute = true)
public String name;
#JacksonXmlProperty(isAttribute = true)
public String data;
//Other Pojo
}
I tried using the #JsonPropertyOrder, but it works only for elements it seems.

Related

Spring Data Mongo DB applying #Indexed(unique = true) on nested object

I want to insert an object (of PayLoad)for each unique timeStamp value in Log . Annotated timeStamp with #Indexed(unique = true, sparse = true) and log with #Valid.
However , I see duplicates getting inserted. The MongoDB collection used is PayLoad.Here's the code snippet. How do I enforce this unique constrain ?
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
#Jacksonized
#Builder
#Document(collection = "PayLoad")
public class PayLoad implements Serializable {
private static final long serialVersionUID = -1238163054776439285L;
#Id
private String payLoadId;
private String sid;
#JsonAlias({"results_link"})
private String resultsLink;
private Result result;
}
import org.springframework.data.annotation.Id;
import javax.validation.Valid;
#Jacksonized
#Builder
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
public class SplunkResult implements Serializable {
private static final long serialVersionUID = -1698863054778439285L;
#Id
String resultId;
#JsonAlias({"DC"})
private String dc;
#JsonAlias({"URL"})
private String url;
private String raw;
private String _raw;
#Valid
private List<Log> log;
}
import org.springframework.data.mongodb.core.index.Indexed;
#Value
#Builder(toBuilder = true)
#Jacksonized
#JsonIgnoreProperties(ignoreUnknown = true)
public class Log implements Serializable {
private static final long serialVersionUID = -5238163054776439285L;
#Id
String logId;
#Indexed(unique = true, sparse = true)
String timeStamp;
String dc;
CallStack stk;
}
Also tried using CompoundIndexes like so , but still it does not work.
#CompoundIndexes({
#CompoundIndex(name = "payload_ts_idx", def = "{'result.perfLog.timeStamp' : 1} ",
unique = true, background = true)})
public class PayLoad implements Serializable {
the index not be created,try update this config.
spring.data.mongodb.auto-index-creation=true

Creating a JAVA Object from XML using Jackson XML for multiple elements with same TAG

I have the following XML Structure which I am using to create a Java Object.
<TABLE NAME="AB" ID="10" CODE="ABC123" RANK="102" YEAR="2022"
TIMESTAMP="2021-05-11-16.19.44.572000">
<TABLE NAME="CD">
<ROW CODE="BCD456" SERIAL="A" ORDER="1" DESCRIPTION_1="TEST1"
DESCRIPTION_2="TEST2 19" DESCRIPTION_3="TEST 3" STATUS_CODE="496" STATUS_INDICATOR="J"
PRODUCT_NAME="SHIP ">
<TABLE NAME="CD1">
<ROW CD1_CODE=" 11N" CD1_DESCRIPTION="T"/>
<ROW CD1_CODE=" 2KA" CD1_DESCRIPTION="T"/>
</TABLE>
<TABLE NAME="CD2">
<ROW CD2_CODE="11" CD2_DESCRIPTION="----"/>
<ROW CD2_CODE="12" CD2_DESCRIPTION="----"/>
<ROW CD2_CODE="35" CD2_DESCRIPTION="----"/>
</TABLE>
<TABLE NAME="CD3"/>
</ROW>
</TABLE>
<TABLE NAME="EF" CODE="EFG789">
<ROW FILE="1" FILE_NAME="TEST.pdf" TIMESTAMP="2021-06-22T08:32:08.055854">
<FILE_DATA>TESTDATA</FILE_DATA>
</ROW>
</TABLE>
</TABLE>
I have created an XMLMapper such as below which retrieves the values from the Java Object. The main issue for me is when I have multiple <TABLE> element in the XML under the same Parent element.
In this first scenario, the <TABLE NAME="AB"> has two child TABLES <TABLE NAME="CD"> and <TABLE NAME="EF">.
In this second scenario, the <TABLE NAME="CD"> has three child TABLES <TABLE NAME="CD1">, <TABLE NAME="CD2"> and <TABLE NAME="CD3"> with subsequent <ROW> of data.
I am trying to use the XMLMapper code provided below along with the neccesary Java Classes to store the relevant data from the XML. I am able to validate the data being stored in the mapper for <TABLE NAME = "CD1"> and it's child elements <ROW>
I have tried the answers suggested in this post, but it doesn't exactly work for my scenario.
Now, I am trying to retrieve and store the elements from <TABLE NAME = "CD2"> and ```. This is where I am getting an error stating
Multiple fields representing property "TABLE": createcsv.elements.CDRow#cd1Table vs createcsv.elements.CDRow#cd2Table
XMLMapperApp.java
public class XmlMapperApp {
public static void main(String[] args) {
try {
File xmlFile = new File("./resource/test.xml").getAbsoluteFile();
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.disable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES);
EmployeeXML employeeXML = xmlMapper.readValue(xmlFile, EmployeeXML.class);
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
}
EmployeeXML.java
#AllArgsConstructor
#NoArgsConstructor
#JacksonXmlRootElement(localName = "TABLE")
public class EmployeeXML {
#JacksonXmlProperty(isAttribute = true, localName = "NAME")
private String name;
#JacksonXmlProperty(isAttribute = true, localName = "ID")
private String id;
#JacksonXmlProperty(isAttribute = true, localName = "CODE")
private String code;
#JacksonXmlProperty(isAttribute = true, localName = "RANK")
private String rank;
#JacksonXmlProperty(isAttribute = true, localName = "YEAR")
private String year;
#JacksonXmlProperty(isAttribute = true, localName = "TIMESTAMP")
private String timestamp;
#JacksonXmlProperty(localName = "TABLE")
private CDTable cdTable;
#JacksonXmlProperty(localName = "TABLE")
private EFTable efTable;
}
RowElement.java
public interface RowElement {
}
CDTable.java
#NoArgsConstructor
#AllArgsConstructor
#JacksonXmlRootElement(localName = "TABLE")
public class CDTable {
#JacksonXmlProperty(isAttribute = true, localName = "NAME")
private String name;
#JacksonXmlProperty(localName = "ROW")
private CDRow cdRow;
}
CDRow.java
#NoArgsConstructor
#AllArgsConstructor
#JacksonXmlRootElement(localName = "ROW")
public class CDRow implements RowElement {
#JacksonXmlProperty(isAttribute = true, localName ="CODE")
private String code;
#JacksonXmlProperty(isAttribute = true, localName ="SERIAL")
private String serial;
#JacksonXmlProperty(isAttribute = true, localName ="ORDER")
private String order;
#JacksonXmlProperty(isAttribute = true, localName ="DESCRIPTION_1")
private String benennung1;
#JacksonXmlProperty(isAttribute = true, localName ="DESCRIPTION_2")
private String benennung2;
#JacksonXmlProperty(isAttribute = true, localName ="DESCRIPTION_3")
private String benennung3;
#JacksonXmlProperty(isAttribute = true, localName ="STATUS_CODE")
private String statusCode;
#JacksonXmlProperty(isAttribute = true, localName ="STATUS_INDICATOR")
private String statusIndicator;
#JacksonXmlProperty(isAttribute = true, localName ="PRODUCT_NAME")
private String productName;
#JacksonXmlProperty(localName = "TABLE")
private CD1Table cd1Table;
#JacksonXmlProperty(localName = "TABLE")
private CD2Table cd2Table;
#JacksonXmlProperty(localName = "TABLE")
private CD3Table cd3Table;
}
CD1Table.java
#NoArgsConstructor
#AllArgsConstructor
#JacksonXmlRootElement(localName = "TABLE")
public class CD1Table {
#JacksonXmlProperty(isAttribute = true, localName = "NAME")
private String name;
#JacksonXmlProperty(localName = "ROW")
private List<CDRow> cd1Row;
}
CD1Row.java
#NoArgsConstructor
#AllArgsConstructor
#JacksonXmlRootElement(localName = "ROW")
public class CD1Row implements RowElement {
#JacksonXmlProperty(isAttribute = true, localName ="CD1_CODE")
private String cd1Code;
#JacksonXmlProperty(isAttribute = true, localName ="CD1_DESCRIPTION")
private String cd1Description;
}
CD2Table.java
#NoArgsConstructor
#AllArgsConstructor
#JacksonXmlRootElement(localName = "TABLE")
public class CD2Table {
#JacksonXmlProperty(isAttribute = true, localName = "NAME")
private String name;
#JacksonXmlProperty(localName = "ROW")
private List<CD2Row> cd2Row;
}
CD2Row.java
#NoArgsConstructor
#AllArgsConstructor
#JacksonXmlRootElement(localName = "ROW")
public class CD2Row implements RowElement {
#JacksonXmlProperty(isAttribute = true, localName ="CD2_CODE")
private String cd2Code;
#JacksonXmlProperty(isAttribute = true, localName ="CD2_DESCRIPTION")
private String cd2Description;
#JacksonXmlProperty(localName = "TABLE")
private CD3Table cd3Table;
}
CD3Table.java
#NoArgsConstructor
#AllArgsConstructor
#JacksonXmlRootElement(localName = "TABLE")
public class CD3Table {
#JacksonXmlProperty(isAttribute = true, localName = "NAME")
private String name;
}
EFTable.java
#NoArgsConstructor
#AllArgsConstructor
#JacksonXmlRootElement(localName = "TABLE")
public class EFTable {
#JacksonXmlProperty(isAttribute = true, localName = "NAME")
private String name;
#JacksonXmlProperty(isAttribute = true, localName = "CODE")
private String code;
#JacksonXmlProperty(localName = "ROW")
private EFRow efRow;
}
EFRow.java
#NoArgsConstructor
#AllArgsConstructor
#JacksonXmlRootElement(localName = "ROW")
public class EFRow implements RowElement {
#JacksonXmlProperty(isAttribute = true, localName ="FILE")
private String file;
#JacksonXmlProperty(isAttribute = true, localName ="FILE_NAME")
private String fileName;
#JacksonXmlProperty(isAttribute = true, localName ="TIMESTAMP")
private String timestamp;
#JacksonXmlProperty(localName ="FILE_DATA")
private String fileData;
}
I would like to know if there is possible way to tackle this scenario along with the other similar scenarios mentioned above, thank you.
Your main TABLE contains tables, and inner TABLE contains rows.
You have different structures to the same tag that is not possible.
Create wrapper TABLES for your inner TABLE, and that`s it

Differences in JSON serialization when loadAll() and loadById(Long id)

I have created Folder class (java springboot), which describes many levels folders' structure for bookmarks managing:
#Entity
#Setter
#Getter
#NoArgsConstructor
#AllArgsConstructor
**public class Folder** implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(cascade = CascadeType.PERSIST)
#JoinColumn(name = "parent_id")
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
private Folder parent;
#OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST)
private List<Folder> children = new ArrayList<>();
private String name;
private String path;
#OneToMany(mappedBy = "folder", cascade = CascadeType.PERSIST)
#JsonManagedReference
private List<Bookmark> bookmarkList = new ArrayList<>();
}
#Entity
#Setter
#Getter
#NoArgsConstructor
#AllArgsConstructor
**public class Bookmark** implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String url;
private String description;
/**
* parent folder
*/
#ManyToOne
#JsonBackReference
private Folder folder;
}
And my problem is that I can see differences in serialized JSON when loadAll() and when loadById(Long id):
#Service
#Transactional
**public class FolderService** {
private FolderRepo folderRepo;
#Autowired
public FolderService(FolderRepo folderRepo) {
this.folderRepo = folderRepo;
}
public void save(Folder folder) {
folderRepo.save(folder);
}
public List<Folder> loadAll() {
List<Folder> folderList = folderRepo.findAll();
return folderList;
}
public Folder loadById(Long id) {
Folder folder = folderRepo.findById(id).get();
return folder;
}
}
#RestController
#RequestMapping("/bookmarks-app")
**public class FolderControllerRest** {
private FolderService folderService;
#Autowired
public FolderControllerRest(FolderService folderService) {
this.folderService = folderService;
}
#GetMapping("/folders/all")
public List<Folder> getFolderListAll() {
List<Folder> folderList = folderService.loadAll();
return folderList;
}
#GetMapping("/folder/{id}")
public Folder getFolderById(
#PathVariable(name = "id") String id
) {
if (!"undefined".equals(id)) {
Long folderId = Long.parseLong(id);
return folderService.loadById(folderId);
} else return null;
}
}
Namely, the difference is ex. in folder.id=2.
When I load all using ajax:
$.ajax({
url: "/bookmarks-app/folders/all",
data: {},
method: "GET",
dataType: "JSON"
});
the parent entity is serialized to its "id" number (as I wanted),
but when use ajax:
$.ajax({
url: "/bookmarks-app/folder/2",
data: {},
method: "GET",
dataType: "JSON"
})
the parent entity is serialized to the object (screenshot below).
screenshoot
I think you are missusing #JsonIdentityInfo, the doc says
#JsonIdentityInfo allows to serialize a POJO by id when it is encountered second time during serialization.
Then in a 'list' mode you get the id, in a single mode you get the whole object.
Maybe you should Use a TypeAdaptor to get the id

Elasticseach type special #JsonIgnore

I have 1 index, 2 types. /spring-boot-1.3.3/
#Document(indexName = "main", type = "item")
#Entity
public class Item {
private Long id;
private String name;
#ManyToOne
private User owner;
}
how can i ignore userData field only for type:"item"
#Document(indexName = "main", type = "user")
#Entity
public class User {
private Long id;
private String userName;
//#JsonIgnore <- ignored for both types, if i add this annotation
private UserData userData; // must be ignored for elastic type: "item"
}

Use abstract super class as parameter for Spring data repository

I know how to implement spring data repositories,
Create an interface like this :
public interface CountryRepository extends CrudRepository<Country, Long> {}
Now Country is an AbstractCatalog and I have (a lot) more catalogs in my project.
I'm wondering if I can make only one repository that would work for all the catalogs:
public interface AbstractCatalogRepository extends CrudRepository<AbstractCatalog, Long> {}
Now I don't see a problem while saving, but if I want to search an AbstractCatalog I'm already sure that I'll hit the wall because the repository will not know which sub-class it must choose.
AbstractCatalog.class
#MappedSuperclass
public abstract class AbstractCatalog extends PersistentEntity {
/**
* The Constant serialVersionUID.
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
/**
* The code.
*/
#Column(unique = true, nullable = false, updatable = false)
private String code;
/**
* The description.
*/
#Column(nullable = false)
private String description;
/**
* The in use.
*/
#Column(name = "IN_USE", nullable = false, columnDefinition = "bit default 1")
private Boolean inUse = Boolean.TRUE;
// getters and setters
}
Country.class
#Entity
#Table(name = "tc_country")
#AttributeOverrides({
#AttributeOverride(name = "id", column =
#Column(name = "COUNTRY_SID")),
#AttributeOverride(name = "code", column =
#Column(name = "COUNTRY_CODE")),
#AttributeOverride(name = "description", column =
#Column(name = "COUNTRY_DESCRIPTION"))})
public class Country extends AbstractCatalog {
public static final int MAX_CODE_LENGTH = 11;
#Column(name = "GEONAMEID", nullable = true, unique = false)
private Long geonameid;
// getter and setter
}
Has anyone any idea, how I could use only ONE repository for all the implementations of AbstractCatalog class without having to create the same interface over and over again with minimal differences in name and other properties?
If you aren't using table inheritance on the database side (e.g. super class table with descriminator column), AFAIK, and based off reading the JPA tutorial, this can't be done (i.e. simply using #MappedSuperclass annotation for your abstract class)
Mapped superclasses cannot be queried and cannot be used in EntityManager or Query operations. You must use entity subclasses of the mapped superclass in EntityManager or Query operations. Mapped superclasses can't be targets of entity relationships
Note, the JPA repository abstraction uses an EntityManager under the hood. I did a simple test, and what you will get (in the case of Hibernate implementation) an "IllegalArgumentException : not an entity AbstractClass"
On the other hand, if you do use table inheritance, then you can use the abstract type. I know you said "with just the minimal change" (and I guess my short answer is I don't think it's possible - probably for the reasons you guessed), so I guess the rest of this answer is for other inquiring minds ;-)
An example of a table inheritance strategy would be something like this (disclaimer: this is not the correct visualization for erd inheritance, but MySQL Workbench doesn't support it, but what I have below forward engineered the model to MYSQL the way it needs to be)
Where CountryCatalog has a FK/PK reference to the AbstractCatalog table pk (id). The AbstractCatalog table has a descriminatorColumn that will be used to determine to which subtype the supertype occurrence is related.
In terms of how you would code that, it would look something like
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name="descriminatorColumn")
#Table(name="AbstractCatalog")
public abstract class AbstractCatalog {
#Id
private long id;
...
}
#Entity
#Table(name = "CountryCatalog")
public class CountryCatalog extends AbstractCatalog {
// id is inherited
...
}
public interface AbstractCatalogRepository
extends JpaRepository<AbstractCatalog, Long> {
}
#Repository
public class CountryCatalogServiceImpl implements CountryCatalogService {
#Autowired
private AbstractCatalogRepository catalogRepository;
#Override
public List<CountryCatalog> findAll() {
return (List<CountryCatalog>)(List<?>)catalogRepository.findAll();
}
#Override
public CountryCatalog findOne(long id) {
return (CountryCatalog)catalogRepository.findOne(id);
}
}
Basically, in conclusion, what you are trying to do won't work if you don't have table inheritance. The class type for the repository needs to be an entity. If your tables aren't set up this way for inheritance, it just comes down to whether or not you want to change the tables. It may be a bit much just to avoid multiple repositories though.
Some references I used are here and here
Note: Everything in this answer is tested against Hibernate provider
Oke, new project and I'm following this set up a little bit.
The problem was :
We want to add attachments, but an attachment can be uploading a file, a link or a mail.
Pojo classes :
Attachment.java :
#Entity
#Table(name = "T_ATTACHMENT")
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "DISCRIMINATOR", discriminatorType = DiscriminatorType.STRING)
public abstract class Attachment {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ATTACHMENT_SID")
private Long id;
#ManyToOne
#JoinColumn(name = "TASK_SID", referencedColumnName = "TASK_SID", nullable = false, unique = false, insertable = true, updatable = true)
private Task task;
#ManyToOne
#JoinColumn(name = "USER_SID", referencedColumnName = "USER_SID", nullable = false, unique = false, insertable = true, updatable = true)
private User user;
public Task getTask() {
return task;
}
public void setTask(Task task) {
this.task = task;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
FileAttachment.java :
#Entity
#Table(name = "T_FILE_ATTACHMENT")
#DiscriminatorValue("FILE")
public class FileAttachment extends Attachment {
#Column(name = "NAME", nullable = false, unique = false)
private String fileName;
#Lob
#Basic
#Column(name = "FILE", nullable = false, unique = false)
private byte[] file;
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public byte[] getFile() {
return file;
}
public void setFile(byte[] file) {
this.file = file;
}
}
MailAttachment.java :
#Entity
#Table(name = "T_MAIL_ATTACHMENT")
#DiscriminatorValue("MAIL")
public class MailAttachment extends Attachment {
#Column(name = "RECIPIENT", nullable = false, unique = false)
private String to;
#Column(name = "CC", nullable = true, unique = false)
private String cc;
#Column(name = "BCC", nullable = true, unique = false)
private String bcc;
#Column(name = "TITLE", nullable = true, unique = false)
private String title;
#Column(name = "MESSAGE", nullable = true, unique = false)
private String message;
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public String getCc() {
return cc;
}
public void setCc(String cc) {
this.cc = cc;
}
public String getBcc() {
return bcc;
}
public void setBcc(String bcc) {
this.bcc = bcc;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
LinkAttachment.java :
#Entity
#Table(name = "T_LINK_ATTACHMENT")
#DiscriminatorValue("LINK")
public class LinkAttachment extends Attachment {
#Column(name = "DESCRIPTION", nullable = true, unique = false)
private String description;
#Column(name = "LINK", nullable = false, unique = false)
private String link;
public String getDescription() {
return description == null ? getLink() : description;
}
public void setDescription(String description) {
this.description = description;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
}
Spring data repo's :
AttachmentRepository.java:
public interface AttachmentRepository extends CustomRepository<Attachment, Long> {
List<Attachment> findByTask(Task task);
}
CustomRepository.java :
public interface CustomRepository<E, PK extends Serializable> extends
PagingAndSortingRepository<E, PK>,
JpaSpecificationExecutor<E>,
QueryDslPredicateExecutor<E> {
#Override
List<E> findAll();
}
And at last the service :
#Service
public class AttachmentServiceImpl implements AttachmentService {
#Inject
private AttachmentRepository attachmentRepository;
#Override
public List<Attachment> findByTask(Task task) {
return attachmentRepository.findByTask(task);
}
#Override
#Transactional
public Attachment save(Attachment attachment) {
return attachmentRepository.save(attachment);
}
}
This results in :
I can save to the abstract repo with any implementation I created, JPA will do it correct.
If I call findByTask(Task task) I get a List<Attachment> of all the subclasses, and they have the correct subclass in the back.
This means, you can make a renderer who do instanceof and you can customize your rendering for each subclass.
Downside is, you still need to create custom specific repository's, but only when you want to query on a specific property what is in the subclass or when you only want 1 specific implementation in stead of all implementations.
What DB are you using?
If it's JPA, take a look at
Can I use a generic Repository for all children of a MappedSuperClass with Spring Data JPA?
If it's Mongo you need to properly tune Jackson polymorphism configuration
http://wiki.fasterxml.com/JacksonPolymorphicDeserialization
So this is possible.

Categories