How to modify existing annotation through spoon in java - java

I am trying to modify my models and remove deprecated annotations. Explained below.
Current Class
Class User{
#Column(name="Name",percision = 3,constraint = "constraint")
private String name;
}
After modification
#Column(name="Name",percision = 3)
private String name;
}
As constraint field in deprecated in annotations I want to remove it keeping rest of the things same.
I am not able to figure out how to do that in spoon.
If any one could help me please share snippets or examples if you have.
Tried editing below code but was not able to retrieve existing annotation and edit.
public class AddNullable {
public static void main(String[] args) {
Launcher spoon = new Launcher();
spoon.addInputResource("field/HasField.java");
spoon.getEnvironment().setAutoImports(true);
spoon.setSourceOutputDirectory(new File("output"));
CtModel model = spoon.buildModel();
Factory factory = spoon.getFactory();
CtAnnotationType nullableAnnotation = (CtAnnotationType) factory.Type().get(Nullable.class);
CtType hasField = model.getRootPackage().getType("HasField");
List<CtField> fields = hasField.getFields();
System.out.println(fields.size());
for (CtField field : fields) {
if (!field.hasAnnotation(Nullable.class) && !field.getType().isPrimitive()) {
System.out.println(field.getSimpleName() + " does not has annotation.");
CtAnnotation an = factory.createAnnotation(nullableAnnotation.getReference());
field.addAnnotation(an);
}
}
spoon.prettyprint();
}
}

Related

What are my options to prevent duplicate code in Java in my case

I got about 6 classes that are doing 'almost' the same with different values. I'll give two classes and an example below and then describe what i'm doing.
public class AttributeRangeRule implements Template {
#Override
public String writeTemplate(BusinessRule businessRule) throws Exception {
String link = TemplateReader.getInstance().getLinkToQuery(businessRule.getBusinessRuleTypeCode());
String template = TemplateReader.getInstance().readQuery(link);
ST templateFixer = new ST(template);
templateFixer.add("code", businessRule.getBusinessRuleTypeCode());
templateFixer.add("attribute_table", businessRule.getListOfTables().get(0).getName());
templateFixer.add("operator", businessRule.getOperator().getName());
templateFixer.add("range_min", businessRule.getListOfValues().get(0).getValue());
templateFixer.add("range_max", businessRule.getListOfValues().get(1).getValue());
templateFixer.add("attribute_column", businessRule.getListOfColumns().get(0).getName());
templateFixer.add("error", businessRule.getErrorMessage());
templateFixer.add("GreaterOrEqual", ">=");
templateFixer.add("LessOrEqual", "<=");
templateFixer.add("LessThen", "<");
templateFixer.add("GreaterThen", ">");
String templateDLL = templateFixer.render();
return templateDLL;
}
}
public class AttributeCompareRule implements Template {
#Override
public String writeTemplate(BusinessRule businessRule) throws Exception {
String link = TemplateReader.getInstance().getLinkToQuery(businessRule.getBusinessRuleTypeCode());
String template = TemplateReader.getInstance().readQuery(link);
ST templateFixer = new ST(template);
templateFixer.add("code", businessRule.getBusinessRuleTypeCode());
templateFixer.add("attribute_table", businessRule.getListOfTables().get(0).getName());
templateFixer.add("operand", businessRule.getOperator().getName());
templateFixer.add("compare_with", businessRule.getListOfValues().get(0).getValue());
templateFixer.add("error", businessRule.getErrorMessage());
String templateDLL = templateFixer.render();
return templateDLL;
}
}
templateFixer.add("code..") is for example duplicate. They are written the same in both classes but the value is different.
I have different classes with different implementation of the method writeTemplate(). As you can see AttributeRangeRule is different from AttributeCompareRule. This code is writting a query for me. Intellij is telling me that the code is duplicate even if the values arent unique. I have no idea how to solve this issue. How can i solve this issue, since duplicate code isnt the best to have in your code. Thanks in advance.
You should try to take advantage of OOPS concepts here and use inheritance here
You can create a base class named AttributeRule that overrides writeTemplate() method and put all the redundant code in there and have this class be extended by your subclasses i.e. AttributeCompareRule and AttributeCompareRule
Here's the conceptual idea and some snippets
public class AttributeRule implements Template {
#Override
public String writeTemplate(BusinessRule businessRule) throws Exception {
String link = TemplateReader.getInstance().getLinkToQuery(businessRule.getBusinessRuleTypeCode());
String template = TemplateReader.getInstance().readQuery(link);
ST templateFixer = new ST(template);
templateFixer.add("code", businessRule.getBusinessRuleTypeCode());
templateFixer.add("attribute_table", businessRule.getListOfTables().get(0).getName());
}
}
public class AttributeCompareRule extends AttributeRule {
#Override
public String writeTemplate(BusinessRule businessRule) throws Exception {
super.writeTemplate(rule);
// Custom class code here
templateFixer.add("operand", businessRule.getOperator().getName());
templateFixer.add("compare_with", businessRule.getListOfValues().get(0).getValue());
templateFixer.add("error", businessRule.getErrorMessage());
String templateDLL = templateFixer.render();
return templateDLL;
}
}
public class AttributeRangeRule extends AttributeRule {
super.writeTemplate(rule);
// Custom class code here
}

Spring-Boot: a #Component class to hold a List of Database table objects

I need to find a proper solution to have a Spring-Boot #Component (singleton) class hold a List of database table objects, which could be accessed throughout the life of an application. I need to get a value of a certain language column value (there could be many language columns) depending on the parameters.
My idea was to do it like this:
#Component
public class CardTypeValueComponent {
private List<CardTypesTabModel> listOfCardTypes;
private CardTypesModelRepository cardTypesModelRepository;
private static final String UNKNOWN = "-";
#Autowired
public CardTypeValueComponent(CardTypesModelRepository cardTypesModelRepository) {
Assert.notNull(cardTypesModelRepository, "CardTypesModelRepository cannot be null");
this.cardTypesModelRepository = cardTypesModelRepository;
}
#PostConstruct
private void getAllCardTypesFromDb() {
this.listOfCardTypes = cardTypesModelRepository.findAll();
}
public String getCardTypeLanguageValue(int cardType, String language) {
String cardTypeLangValue = UNKNOWN;
for (CardTypesTabModel cardTypesTabModel : listOfCardTypes) {
if (cardTypesTabModel.getTypeId() == cardType && "spanish".equals(language)) {
cardTypeLangValue = cardTypesTabModel.getSpanishValue();
} else {
cardTypeLangValue = cardTypesTabModel.getEnglishValue();
}
}
return cardTypeLangValue;
}
}
Is it a proper way of completing such a task whilst keeping in mind that the table object column count could increase in the future?
Excuse me for the pseudo code. Thanks.
Added more details:
CardTypesTabModel Entity class:
#Entity
public class CardTypesTabModel {
private int type;
private String englishValue;
private String spanishValue;
// other values, getters & setters
}
What you're trying to do is re-inventing the caching mechanisme.
You may consider to relay on the Spring Cache Abstraction http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html then choose JCache (JSR-107) as implementation.

Getting multiple XML elements with the same name JAXB

probably a stupid question, but I'm stuck.
I try do parse a huge xml document retrieved from a REST service.
What I'm interested in are both the abstract parts.
<article article-type="research-article">
<front>
<article-meta>
<abstract></abstract>
<abstract abstract-type="summary"></abstract>
</article-meta>
</front>
</article>
In my front class, I do the following:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement
public class Front {
#XmlElementWrapper(name = "article-meta")
#XmlElement(name="abstract")
private List<AuthorSummary> authorSummaries = new ArrayList<AuthorSummary>();
/** Getter and Setter **/
}
Sadly, I only the get the first abstract, but there the content as well. You can see my AuthorSummary Class below.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement
public class AuthorSummary {
#XmlElement(name = "title")
private String title;
#XmlElement(name = "p")
private String content;
#XmlAttribute(name = "abstract-type")
private String abstractType;
/** Getter and Setter **/
}
So, I'm stuck and would be very glad for any hints.
Thank you very much
I have a solution, but it is not using jaxb or even data binding at all. So if you are stuck to data binding I will delete my answer. Otherwise, I like you point to data projection (Disclosure: I am affiliated with that project) instead of data binding:
public class ReadElementsWithSameName {
public interface Article {
#XBRead("./#article-type")
String getType();
#XBRead("./front/article-meta/abstract")
List<String> getAllAbstracts();
#XBRead("./front/article-meta/abstract[#abstract-type='summary']")
String getSummary();
}
// Configure the underlying document builder to not load the (nonexisting) DTD
private static final XMLFactoriesConfig nonValidatingConfig = new DefaultXMLFactoriesConfig() {
#Override
public DocumentBuilderFactory createDocumentBuilderFactory() {
DocumentBuilderFactory factory = super.createDocumentBuilderFactory();
try {
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
} catch (ParserConfigurationException e) {
throw new RuntimeException(e);
}
return factory;
}
};
public static void main(String... args) throws IOException {
List<Article> articles = new XBProjector(nonValidatingConfig).io().url("res://data.xml").evalXPath("/article").asListOf(Article.class);
for (Article article:articles) {
System.out.println(article.getType());
System.out.println(article.getSummary());
System.out.println(article.getAllAbstracts());
}
}
}
Instead of reflecting the XML structure with java classes, just define the Java API as a "projection interface" with the accessors (and setters) you like to have. Afterwards, let the projection framework take care of reading and writing your changes to the DOM.

Constructor not defined during Test

I am having a pesky error testing this piece of code.Not sure what I am doing wrong. I have tested standard controllers before but not the getSelectedMethod
Error:
Constructor not defined:[myClass].(ApexPages.StandardController)
public class MyClass{
public List<Web__c> postings {get;set;}
public static final String POSTINGSTATUS = 'Yes';
public MyClass (ApexPages.StandardSetController controller) {
List<Web__c> selectedWeb = (List<Web__c>) controller.getSelected();
postings = [Select Id, Name,
FROM Web___c Where Id IN: selectedWeb
AND Date__c != null
AND Date__c > today];
}
}
My Test Class
private class myTestClass {
static testMethod void WebTest() {
List <Web__c> posting = helper.createWeb(4);
insert posting;
Test.startTest();
PageReference pageRef = Page.VFPAGE;
Test.setCurrentPage(pageRef);
ApexPages.StandardController sc = new ApexPages.standardController(posting[0]);
myClass JPC = new myClass(sc);
sc.setSelected(posting);
Test.stopTest();
}
new ApexPages.standardController(posting[0]) looks wrong to me.
It should likely be new ApexPages.StandardSetController(posting[0]) if you want to create a new instance of ApexPages.StandardSetController, or just ApexPages.standardController(posting[0]) (without the new) if it's a static method that returns such an instance.
BTW: you should state what error you get and where in the code it occurs when asking such a question, as figuring it out without that information is pretty hard. I just found this by chance, I'd asked for that information otherwise.

Jackson Change JsonIgnore Dynamically

I have a class and there are variables inside it as well. Sometimes I want to ignore some fields and sometimes not when deserializing (maybe at serializing too). How can I do it at Jackson?
For serialization, "filtering properties" blog entry should help. Deserialization side has less support, since it is more common to want to filter out stuff that is written.
One possible approach is to sub-class JacksonAnnotationIntrospector, override method(s) that introspect ignorability of methods (and/or fields) to use whatever logic you want.
It might also help if you gave an example of practical application, i.e what and why you are trying to prevent from being deserialized.
You might want to use JsonViews ( took it originally from http://wiki.fasterxml.com/JacksonJsonViews - broken now - web archive link: https://web.archive.org/web/20170831135842/http://wiki.fasterxml.com/JacksonJsonViews )
Quoting it:
First, defining views means declaring classes; you can reuse existing ones, or just create bogus classes -- they are just view identifiers with relationship information (child inherits view membership from parents):
// View definitions:
class Views {
static class Public { }
static class ExtendedPublic extends PublicView { }
static class Internal extends ExtendedPublicView { }
}
public class Bean {
// Name is public
#JsonView(Views.Public.class) String name;
// Address semi-public
#JsonView(Views.ExtendPublic.class) Address address;
// SSN only for internal usage
#JsonView(Views.Internal.class) SocialSecNumber ssn;
}
With such view definitions, serialization would be done like so:
// short-cut:
objectMapper.writeValueUsingView(out, beanInstance, ViewsPublic.class);
// or fully exploded:
objectMapper.getSerializationConfig().setSerializationView(Views.Public.class);
// (note: can also pre-construct config object with 'mapper.copySerializationConfig'; reuse)
objectMapper.writeValue(out, beanInstance); // will use active view set via Config
// or, starting with 1.5, more convenient (ObjectWriter is reusable too)
objectMapper.viewWriter(ViewsPublic.class).writeValue(out, beanInstance);
and result would only contain 'name', not 'address' or 'ssn'.
You should probably look at the modules feature of recent Jackson versions.
One possible mechanism would be to use a BeanDeserializerModifier.
I've been looking for a useful online tutorial or example, but nothing immediately appears. It might be possible to work something up if more is known of your context. Are you managing your ObjectMappers manually, or using them in a JAX-RS setting, injected in Spring, or what?
I searched the entire web (yes I did) to find the answer. then I wrote something on my own.
I'm working with Jackson ion deserialisation. I wrote a custom reader that ignores the fields dynamically.
You can do the same thing for json deserialisation.
Lets assume an entity like this.
User {
id
name
address {
city
}
}
Create a tree structure to represent field selection.
public class IonField {
private final String name;
private final IonField parent;
private final Set<IonField> fields = new HashSet<>();
// add constructs and stuff
}
Custom Ion Reader extending from amazon ion-java https://github.com/amzn/ion-java
public class IonReaderBinaryUserXSelective extends IonReaderBinaryUserX {
private IonField _current;
private int hierarchy = 0;
public IonReaderBinaryUserXSelective(byte[] data, int offset, int length,
IonSystem system, IonField _current) {
super(system, system.getCatalog(), UnifiedInputStreamX.makeStream(data, offset, length));
this._current = _current;
}
#Override
public IonType next() {
IonType type = super.next();
if (type == null) {
return null;
}
String file_name = getFieldName();
if (file_name == null || SystemSymbols.SYMBOLS.equals(file_name)) {
return type;
}
if (type == IonType.STRUCT || type == IonType.LIST) {
IonField field = _current.getField(getFieldName());
if (field != null) {
this._current = field;
return type;
} else {
super.stepIn();
super.stepOut();
}
return next();
} else {
if (this._current.contains(file_name)) {
return type;
} else {
return next();
}
}
}
#Override
public void stepIn() {
hierarchy = (hierarchy << 1);
if (getFieldName() != null && !SystemSymbols.SYMBOLS.equals(getFieldName())) {
hierarchy = hierarchy + 1;
}
super.stepIn();
}
#Override
public void stepOut() {
if ((hierarchy & 1) == 1) {
this._current = this._current.getParent();
}
hierarchy = hierarchy >> 1;
super.stepOut();
}
Construct dynamic view. This Tree dynamically created and passed to the reader to deserialise.
Let's say we only need city inside the address.
IonField root = new IonField("user", null);
IonField address = new IonField("address", root);
IonField city = new IonField("city", address);
address.addChild(city);
root.addChild(id);
//now usual stuff.
IonFactory ionFactory = new IonFactory();
IonObjectMapper mapper = new IonObjectMapper(ionFactory);
File file = new File("file.bin"); // ion bytes
byte[] ionData = Files.readAllBytes(file.toPath());
IonSystem ionSystem = IonSystemBuilder.standard().build();
IonReader ionReader = new IonReaderBinaryUserXSelective(ionData, 0, ionData.length, ionSystem, root);
User user = mapper.readValue(ionReader, User.class);

Categories