Abbreviating text in Freemarker - freemarker

I want to achieve the equivalent of the StringUtils.abbreviate(String, int) method in Freemarker.
I am generating per-user SMS text using Freemarker templates. Most of the text is static but it contains fields that have a maximum character size. For these fields I need to be able to do the equivalent of:
Hello, ${abbrev(userName, 15)}, welcome to the wonderful world of example.com.
Keep in mind: this is just an example.
As a first cut, I tried doing it using this sample as a guide:
public class AbbreviateMethod implements TemplateMethodModelEx {
#Override
public Object exec(#SuppressWarnings("rawtypes") List arguments) throws TemplateModelException {
if (arguments.size() < 2)
throw new TemplateModelException("Needs 2 parameters");
return (abbreviate((String) arguments.get(0), ((Integer) arguments.get(1)).intValue()));
}
}
but I get the exception:
java.lang.ClassCastException: freemarker.template.SimpleScalar cannot be cast to java.lang.String
at com.example.util.AbbreviateMethod.exec(AbbreviateMethod.java:26)
at freemarker.core.MethodCall._eval(MethodCall.java:65)
at freemarker.core.Expression.eval(Expression.java:81)
at freemarker.core.DollarVariable.calculateInterpolatedStringOrMarkup(DollarVariable.java:96)
at freemarker.core.DollarVariable.accept(DollarVariable.java:59)
at freemarker.core.Environment.visit(Environment.java:327)
at freemarker.core.Environment.visit(Environment.java:333)
at freemarker.core.Environment.process(Environment.java:306)
Any ideas?

You need to explicit call SimpleScalar toString() to convert to String
Change your line to :
return (abbreviate(arguments.get(0).toString(), ((Integer) arguments.get(1)).intValue()));

Related

I need help i keep geting this unity error? Assets\ScoreTextScript.cs(10,10): error CS0426: The type name 'Text' does not exist in the type 'Text'

So this is my code. Im trying to make it so the coins collected add to the score in the UI.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ScoreTextScript : MonoBehaviour
{
Text.Text
coinAmount;
//Use this for initialization
void Start ()
{
text = GetComponent<Text>();
}
//Update is called once per frame
void Update ()
{
text.Text = coinAmount;
}
}
The Text is the error but I don't know how to fix it.
I need help immediately
I think you don't understand how variables work in unity.
First you are declaring a Text.text called coinAmount
In Unity when you are declaring a variable you first have to set the access modifier.
The 2 main are: private and public.
private means your variable will only be accessible in the class you declared it.
public means you can access it from any other class if you make a reference to that script.
Then you need to put the type of your variable.
Here you used Text.text and that's not a type for a variable.
You can set to int, string, etc... If you want to use a Text component in unity do like this:
private Text coinAmount;
Since it's a private variable you can't drag it in the editor. If you want to be able to place a Text component by hand in the editor you can either do:
public Text coinAmount;
//or
[SerializeField] private Text coinAmount; //I'll let you search about SerializeField
In your Start method you are assigning text variable to the Text component this object hold. But text does not exist. If you declare a variable in a method it will only be accessible in this method.
So, what you want is:
private void Start(){
coinAmount = GetComponent<Text>();
}
And lastly i see you want to assign your text to the variable we created earlier. That's useless. You need to create a new variable of type int and assign it to the text value of coinAmount.
To do so:
We will create a new variable right under coinAmount.
public int coinNumber;
And in update we can use it:
private void Update(){
coinAmount.text = coinNumber.ToString(); //.ToString() is used when you want to convert something to a string (which is a type of variable).
}
And there we go everything should work correctly !
The whole code:
private Text coinAmount;
public int coinNumber;
private void Start(){
coinAmount = GetComponent<Text>();
}
private void Update(){
coinAmount.text = coinNumber.ToString(); //.ToString() is used when you want to convert something to a string (which is a type of variable).
}
Hope it helped ! Have a nice day !

String cannot be cast to an Iterable error?

So I'm attempting to go through a groovyObject's fields and obtain the property of that field. So this is what I got(sorry its a little rough so cleaning would be appreciated but not necessary, I'm also doing a little debugging and other stuff with the Log and what not.):
public void traverse(final GroovyObject groovy) throws RepositoryException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException
{
Field[] theFields = groovy.getClass().getDeclaredFields();
final ArrayList<Field> fields = new ArrayList<Field>();
int count =0;
for(Field field : theFields)
{
fields.add(field);
LOG.error("{} = {}",field.getName(), groovy.getProperty(field.getName()));
}
//this is the guava tree traverser
TreeTraverser<GroovyObject> traverser = new TreeTraverser<GroovyObject>()
{
#Override
public Iterable<GroovyObject> children(GroovyObject root)
{
return (Iterable<GroovyObject>)root.getProperty(fields.get(0).getName());
//|-->Here I get the String cannot be cast to Iterable. Which I find odd since it is still an object just getProperty takes a string. right?
}
};
Thoughts on this? Thanks for the help!
GroovyObject.getProperty(String) retrieves the value of the given property. And if that value happens to be a String you cannot cast it to Iterable.
If you adjust your log statement, you can inspect the types of the fields:
LOG.error("{} of type {} = {}", field.getName(), field.getType(), groovy.getProperty(field.getName()));
So I figured it outl. Essentially what needs to happen is I need to make two iterators: one for the groovy objects and one for the property strings so the end goal looks like
groovyObject.iterate().next().getProperty(string.iterate().next());
Or something like that, I will update this when I figure it out.!
Once I make that I can go back in and think about making it more efficient

Spring Repository method complains about field not found

I'm using Spring Data Neo4j in my project and I'm having issues with naming conventions for repositories.
This is a simple class containing only one field and the getters/setters
#RelationshipEntity
public class ScoredRelationship
{
protected Float score;
}
and the class below extends it with other kind of fields
#RelationshipEntity(
type = RecommenderRelTypes.GOV_CONSUMER_TO_GOV_CONSUMER_SIMILARITY)
public class GovConsumerToGovConsumerSimilarity extends ScoredRelationship
{ // Other fields}
To access the relationship, I'm using the usual repository class
public interface GovConsumerToGovConsumerSimilarityRepository extends
GraphRepository<GovConsumerToGovConsumerSimilarity>
{
public Set<GovConsumerToGovConsumerSimilarity> findByScoreGreaterThan(Float value);
public Set<GovConsumerToGovConsumerSimilarity>
findByScoreGreaterThanOrderByScoreDesc(Float value);
public Set<GovConsumerToGovConsumerSimilarity>
findTopXByScoreGreaterThanOrderByScoreDesc(int limit, Float score);
}
This code compiles well. However, whenever I'm trying to use one of the methods, Spring return a series of exception or doesn't act as intended.
F.e. #findByScoreGreaterThan(0.3f) always returns an empty set. However, invoking a findAll() and printing all the scores it actually has a lot of objects with a score greater than 0.3.
In the second and third case, it always throws an exception saying
Caused by: Unknown identifier `score`.
at org.neo4j.cypher.internal.symbols.SymbolTable.evaluateType(SymbolTable.scala:60)
at org.neo4j.cypher.internal.commands.expressions.Identifier.evaluateType(Identifier.scala:51)
at org.neo4j.cypher.internal.commands.expressions.Expression.assertTypes(Expression.scala:53)
at org.neo4j.cypher.internal.pipes.SortPipe$$anonfun$assertTypes$1.apply(SortPipe.scala:34)
at org.neo4j.cypher.internal.pipes.SortPipe$$anonfun$assertTypes$1.apply(SortPipe.scala:33)
at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
at scala.collection.immutable.List.foreach(List.scala:45)
at org.neo4j.cypher.internal.pipes.SortPipe.assertTypes(SortPipe.scala:33)
at org.neo4j.cypher.internal.pipes.PipeWithSource.<init>(PipeWithSource.scala:27)
at org.neo4j.cypher.internal.pipes.SortPipe.<init>(SortPipe.scala:29)
at org.neo4j.cypher.internal.executionplan.builders.SortBuilder.apply(SortBuilder.scala:33)
at org.neo4j.cypher.internal.executionplan.ExecutionPlanImpl.prepareExecutionPlan(ExecutionPlanImpl.scala:49)
at org.neo4j.cypher.internal.executionplan.ExecutionPlanImpl.<init>(ExecutionPlanImpl.scala:33)
at org.neo4j.cypher.ExecutionEngine$$anonfun$prepare$1.apply(ExecutionEngine.scala:67)
at org.neo4j.cypher.ExecutionEngine$$anonfun$prepare$1.apply(ExecutionEngine.scala:67)
at org.neo4j.cypher.internal.LRUCache.getOrElseUpdate(LRUCache.scala:37)
at org.neo4j.cypher.ExecutionEngine.prepare(ExecutionEngine.scala:67)
at org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:59)
at org.neo4j.cypher.ExecutionEngine.execute(ExecutionEngine.scala:63)
at org.neo4j.cypher.javacompat.ExecutionEngine.execute(ExecutionEngine.java:79)
at org.springframework.data.neo4j.support.query.CypherQueryEngine.parseAndExecuteQuery(CypherQueryEngine.java:61)
How could be possible? I mean, the class obviously has the score field. Also, executing the simple #findByScoreGreaterThan(float value) doesn't throw any exception, but at the same the latter method always returns an empty set.
EDIT:
These are the queries used by Spring. Actually, they seems right
Executing cypher query: START `govConsumerToGovConsumerSimilarity`=node:__types__(className="it.cerict.recommender.persistence.neo4j.GovConsumerToGovConsumerSimilarity") WHERE `govConsumerToGovConsumerSimilarity`.`score`! > {0} RETURN `govConsumerToGovConsumerSimilarity` params {0=0.3}
Executing cypher query: START `govConsumerToGovConsumerSimilarity`=node:__types__(className="it.cerict.recommender.persistence.neo4j.GovConsumerToGovConsumerSimilarity") WHERE `govConsumerToGovConsumerSimilarity`.`score`! > {0} RETURN `govConsumerToGovConsumerSimilarity` ORDER BY score DESC params {0=0.3}
EDIT2: I've also tried to change the score type from Float to float with no further improvements.
This seems to be a bug related to Spring Data Neo4j. Looking to the query executed, it is clear that it searches for nodes, while it should search for relationships.
I changed the #findByScoreGreaterThanOrderByScoreDesc() method using the #Query annotation that specifies the following Cypher query
START `govConsumerToGovConsumerSimilarity`=rel:__rel_types__(className="it.cerict.recommender.persistence.neo4j.GovConsumerToGovConsumerSimilarity") WHERE `govConsumerToGovConsumerSimilarity`.`score`! > 0.3 RETURN `govConsumerToGovConsumerSimilarity` ORDER BY `govConsumerToGovConsumerSimilarity`.`score` DESC;

Validation Error: value is not valid when using a custom converter [duplicate]

This question already has answers here:
Validation Error: Value is not valid
(3 answers)
Closed 6 years ago.
NetBeans 7.1.1 JSF2.1
When using converter="convK" attribute in h:selectManyCheckBox it all works well. But I tried to use #FacesConverter(forClass=className.class) form and it keeps giving me "Validation is not Valid" errors. I've tried changing it to forClass=packageName.className.class but no help.
This is converter:
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
#FacesConverter( "convK")
public class KorisnikConverter implements Converter{
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value==null) return value;
if (value.isEmpty()) return value;
for (int i=0; i<Arhiva.getSviKor().size(); i++) {
if (Arhiva.getSviKor().get(i).getUsername().equals(value)) {
return Arhiva.getSviKor().get(i);
}
}
return value;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value==null) return "";
if (value instanceof Korisnik) return ((Korisnik)value).getUsername();
return "";
}
}
I have a class called Korisnik which has couple text fields, username is unique one. In my main managing bean I have couple arrayList of those objects. Goal is to use selectManyCheckBox to chose just some of users and put them in a separate arraylist for some other uses. I wanted to push entire objects around (I can always easily work with strings and have object creation and management in my controler beans but wanted to try custom converters to get selectItems to work with objects)
In my class I've overridden equals and hashCode (as there is a lot of talk about custom converters giving blah blah Validation is not valid errors).
#Override
public boolean equals (Object obj) {
if (obj==null) return false;
if (!(obj instanceof Korisnik)) return false;
Korisnik k = (Korisnik)obj;
return (this.username==k.username);
}
#Override
public int hashCode() {
return this.username.hashCode();
}
Edit. When I'm using it as named converter and using said converter only in that one instance with selectManyCheckbox it works fine even without overriding equals and hashCode.
This is checkbox code
<h:selectManyCheckbox value="#{kontrolg.izabrAut}" layout="pageDirection" converter="convK" >
<f:selectItems value="#{kontrolg.moguciAut}" var="it" itemLabel="# {it.ime} #{it.prezime}" itemValue="#{it}"/>
</h:selectManyCheckbox>
What I don't know is whether I'm failing to properly use forClass="whatever" in converter annotation or my converter actually works ok with that one selectManyCheckbox, but when I specify it in forClass form it gets used for all instances of that object and causes some other code that worked nice before adding custom converters to now give "validation is not valid" error?
The value is not valid validation error will be thrown when the equals() method on the selected item has not returned true for any of the available items.
And indeed, your equals() method is broken. The following line is wrong:
return (this.username==k.username);
I'll assume that username is a String, which is an Object. The == compares Objects by reference, not by their value. In other words, when performing == on two Objects, you're basically testing if they point to exactly the same instance. You're not checking if they represent the same value (say, the Object instance's internal representation). You should be using the Object's equals() method instead, the String#equals() method, here's an extract of relevance from its javadoc:
equals
public boolean equals(Object anObject)
Compares this string to the specified object. The result is true if and only if the argument is not null and is a String object that represents the same sequence of characters as this object.
The == is only applicable when comparing primitives like boolean, int, long, etc or when testing for null.
So, to fix your problem, replace the wrong line by the following line:
return username.equals(k.username);
Or, when they can possibly be null:
return (username == null) ? (k.username == null) : username.equals(k.username);
See also:
Right way to implement equals contract

XmlReader.ReadContentAsObject always returns string type

According to the MSDN documentation, XMLWriter.WriteValue writes xsd type information to the xml for simple CLR types. Then XMLReader.ReadContentAsObject supposedly reads out the appropriately-typed object when the XML is parsed. However, this always seems to return a string object for me and the ValueType property of the XMLReader is string. I've tried inserting longs and DateTimes, but they always end up as strings. Any ideas what I'm doing wrong or is this a Windows Phone bug?
XML Writing Code
public void WriteXml(XmlWriter writer) {
// KeyValuePair<string, object> pair initialized previously
writer.WriteStartElement(pair.Key);
writer.WriteValue(pair.Value)
writer.WriteEndElement();
}
XML Parsing Code
public void ReadXml(XMLReader reader) {
while (reader.Read()) {
if (reader.NodeType == XmlNodeType.Element) {
Type T = reader.ValueType; // T is string
reader.ReadStartElement();
object o = reader.ReadContentAsObject(); // o is string
o = reader.ReadContentAs(T, null); // o is string
}
}
}
You need to use a schema file (XSD) so that the framework can infer the type of a node. Otherwise ValueType will always return System.String.
MSDN says:
If a validation error occurs while parsing the content and the reader is an XmlReader object created by the Create method, the reader returns the content as a string. In other words when a validation error or warning occurs, the content is considered to be untyped.
I was making this too difficult. My goal was to serialize a Dictionary with generic type (string, object) by traversing its KeyValuePairs , but that class doesn't seem to be serializeable using XmlSerializer. I just created another class with two public properties, Key and Value, so I could use XmlSerializer. When deserializing with XmlSerializer, the type of Value is restored as long as it is a supported CLR type.
public void WriteXml(XmlWriter writer) {
// KeyValuePair<string, object> pair initialized previously
writer.WriteStartElement("entry");
MyClass toSerialize = new MyClass(pair.Key, pair.Value);
XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
serializer.Serialize(writer, toSerialize);
writer.WriteEndElement();
}

Resources