Should be pretty simple: I have an InputStream where I want to peek at (not read) the first two bytes, i.e. I want the "current position" of the InputStream to stil be at 0 after my peeking. What is the best and safest way to do this?
Answer - As I had suspected, the solution was to wrap it in a BufferedInputStream which offers markability. Thanks Rasmus.
For a general InputStream, I would wrap it in a BufferedInputStream and do something like this:
BufferedInputStream bis = new BufferedInputStream(inputStream);
bis.mark(2);
int byte1 = bis.read();
int byte2 = bis.read();
bis.reset();
// note: you must continue using the BufferedInputStream instead of the inputStream
You might find PushbackInputStream to be useful:
http://docs.oracle.com/javase/6/docs/api/java/io/PushbackInputStream.html
When using a BufferedInputStream make sure that the inputStream is not already buffered, double buffering will cause some seriously hard to find bugs.
Also you need to handle Readers differently, converting to a StreamReader and Buffering will cause bytes to be lost if the Reader is Buffered.
Also if you are using a Reader remember that you are not reading bytes but characters in the default encoding (unless an explicit encoding was set).
An example of a buffered input stream, that you may not know is URL url; url.openStream();
I do not have any references for this information, it comes from debugging code.
The main case where the issue occurred for me was in code that read from a file into a compressed stream.
If I remember correctly once you start debugging through the code there are comments in the Java source that certain things do not work correctly always.
I do not remember where the information from using BufferedReader and BufferedInputStream
comes from but I think that fails straight away on even the simplest test.
Remember to test this you need to be marking more than the buffer size (which is different for BufferedReader versus BufferedInputStream), the problems occur when the bytes being read reach the end of the buffer.
Note there is a source code buffer size which can be different to the buffer size you set in the constructor.
It is a while since I did this so my recollections of details may be a little off.
Testing was done using a FilterReader/FilterInputStream, add one to the direct stream and one to the buffered stream to see the difference.
I found an implementation of a PeekableInputStream here:
http://www.heatonresearch.com/articles/147/page2.html
The idea of the implementation shown in the article is that it keeps an array of "peeked" values internally. When you call read, the values are returned first from the peeked array, then from the input stream. When you call peek, the values are read and stored in the "peeked" array.
As the license of the sample code is LGPL, It can be attached to this post:
package com.heatonresearch.httprecipes.html;
import java.io.*;
/**
* The Heaton Research Spider Copyright 2007 by Heaton
* Research, Inc.
*
* HTTP Programming Recipes for Java ISBN: 0-9773206-6-9
* http://www.heatonresearch.com/articles/series/16/
*
* PeekableInputStream: This is a special input stream that
* allows the program to peek one or more characters ahead
* in the file.
*
* This class is released under the:
* GNU Lesser General Public License (LGPL)
* http://www.gnu.org/copyleft/lesser.html
*
* #author Jeff Heaton
* #version 1.1
*/
public class PeekableInputStream extends InputStream
{
/**
* The underlying stream.
*/
private InputStream stream;
/**
* Bytes that have been peeked at.
*/
private byte peekBytes[];
/**
* How many bytes have been peeked at.
*/
private int peekLength;
/**
* The constructor accepts an InputStream to setup the
* object.
*
* #param is
* The InputStream to parse.
*/
public PeekableInputStream(InputStream is)
{
this.stream = is;
this.peekBytes = new byte[10];
this.peekLength = 0;
}
/**
* Peek at the next character from the stream.
*
* #return The next character.
* #throws IOException
* If an I/O exception occurs.
*/
public int peek() throws IOException
{
return peek(0);
}
/**
* Peek at a specified depth.
*
* #param depth
* The depth to check.
* #return The character peeked at.
* #throws IOException
* If an I/O exception occurs.
*/
public int peek(int depth) throws IOException
{
// does the size of the peek buffer need to be extended?
if (this.peekBytes.length <= depth)
{
byte temp[] = new byte[depth + 10];
for (int i = 0; i < this.peekBytes.length; i++)
{
temp[i] = this.peekBytes[i];
}
this.peekBytes = temp;
}
// does more data need to be read?
if (depth >= this.peekLength)
{
int offset = this.peekLength;
int length = (depth - this.peekLength) + 1;
int lengthRead = this.stream.read(this.peekBytes, offset, length);
if (lengthRead == -1)
{
return -1;
}
this.peekLength = depth + 1;
}
return this.peekBytes[depth];
}
/*
* Read a single byte from the stream. #throws IOException
* If an I/O exception occurs. #return The character that
* was read from the stream.
*/
#Override
public int read() throws IOException
{
if (this.peekLength == 0)
{
return this.stream.read();
}
int result = this.peekBytes[0];
this.peekLength--;
for (int i = 0; i < this.peekLength; i++)
{
this.peekBytes[i] = this.peekBytes[i + 1];
}
return result;
}
}
Related
I throw a bunch of custom runtime exceptions in my code and I want to make sure that in all public methods, I document which runtime exception might be thrown (by myself) and why. This would be very hulpful since I'm maintaining a library which is used by many projects and I want it to be upfront and predictable regarding thrown (runtime) exceptions.
Is there a compiler option, maven plugin, Intellij plugin or custom tool that can help me find missed throws clauses? With checked exceptions it's easy, the compiler will just complain if I missed one, but for runtime exceptions both throws and #throws are not enforced.
One thing I thought of was to temporarily make all my own runtime exceptions checked exceptions (they already share a super class), but that would be a one-off exercise. I would like to verify my code/documentation each time I make changes so I can never forget to document my runtime exceptions.
Another way could be to actually have checked exceptions throughout the code and convert them to runtime only in the public api:
class Foo {
// oops, throws not documented with #throws
public void publicMethod() {
try {
privateMethod1();
} catch (CheckedFooException e) {
throw new RuntimeFooException(e);
}
}
private void privateMethod1() throws CheckedFooException {
privateMethod2();
}
private void privateMethod2() throws CheckedFooException {
throw new CheckedFooException();
}
}
This approach would force me to think about CheckedFooException in all public methods. Then to check if I missed documenting one (ie. #throws RuntimeFooException), I would simply do a regex search on catch.*CheckedFooException and check for missing #throws entries. Rather unwieldy process though (and there's a lot of public api that would get peppered with try...catch statements).
Answer: There is some discussion about whether you should document (your own thrown) runtime exceptions at all (the summary so far: it depends), but as far as a direct answer to my question, the accepted answer answers it adequately; I can take that approach, implement my use case and even make a maven plugin with it, given some time and effort. I uploaded a cleaned up start project for this.
After understanding your question and researching this subject, I finally found what I thought to be one of the best tools to do this job. With this not only you can find each throws instance that you haven't documented, but you can also find where you don't throw anything but accidentally document a throw value.
The idea behind this is to parse the code into an abstract syntax tree. Then look for methods and look for throws statement in the methods. If a method have any throw statement, extract the exception name from those statements. Then get the Javadoc for that method. Check the Javadoc for all the #throw tags and get the name of the exception that been documented. After that, compare the exception throws versus the one that been documented. The last, you kind of have to figure that out on your own depend on your usage circumstance.
The tool I used for this is JavaParser. You can find them on Github at https://github.com/javaparser/javaparser. I downloaded their latest version. Their website is at https://javaparser.org/. They wrote a book on this subject and they mentioned that you can pay $0 dollar for the book. However, I didn't read that as they also have a Javadoc version for their program which can be found at https://www.javadoc.io/doc/com.github.javaparser/javaparser-core/3.15.1.
I wrote a demonstrate code below. In no mean that this code is final. It is just an example. You have to fix it into making it work for your case. I didn't take into consideration of nested classes, nested method, or methods within classes that are within a method. Also, the example code was written for class only and not interface. However, it is easy to adapt the code to change to able to handle interfaces.
For this, you would need to download javaParser, build it, and have their javaparser-core-3.15.1.jar or whichever version in your classpath.
The demonstrated code is below and the test.java is a file from a project that I wrote but you could use any. I also included comments in the example code.
import com.github.javaparser.*;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.comments.*;
import com.github.javaparser.ast.stmt.*;
import com.github.javaparser.ast.body.*;
import com.github.javaparser.javadoc.*;
import java.io.IOException;
import java.nio.file.*;
import java.nio.charset.Charset;
import java.util.*;
import java.util.stream.Collectors;
class Main{
public static void main(String[] args) throws IOException {
// Set file path
Path path = Paths.get("test.java");
// Set configuration
ParserConfiguration parseConfig = new ParserConfiguration();
parseConfig.setCharacterEncoding(Charset.forName("UTF-8"));
parseConfig.setTabSize(4);
parseConfig.setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_8);
// Get the parser
JavaParser jvParser = new JavaParser(parseConfig);
// Parse the result
ParseResult<CompilationUnit> parseResult = jvParser.parse(path);
// Check for problem
if ( !parseResult.isSuccessful() ) {
System.out.print("Parsing java code fail with the following problems:");
List<Problem> problems = parseResult.getProblems();
for ( Problem problem : problems ){
System.out.println(problem.getMessage());
}
return;
}
// Get the compilationUnit
// No optional checking for Optional<CompilationUnit> due to already check above.
CompilationUnit compilationUnit = parseResult.getResult().get();
// Get Classes
List<ClassOrInterfaceDeclaration> classes = compilationUnit.findAll(ClassOrInterfaceDeclaration.class).stream()
.filter(c -> !c.isInterface())
.collect(Collectors.toList());
// Traverse through each class to get method
for ( ClassOrInterfaceDeclaration c : classes ) {
// Get methods
List<MethodDeclaration> methods = c.getMethods();
for ( MethodDeclaration method : methods ) {
// Get the body statement
Optional <BlockStmt> body = method.getBody();
// if no body continue
if ( !body.isPresent() ) continue;
// After getting the body of the method code
// Search for the throw statements.
List<ThrowStmt> throwStatements = body.get().findAll(ThrowStmt.class);
// No throw statements, skip
if ( throwStatements.size() == 0 ) continue;
// Storing name of exceptions thrown into this list.
List<String> exceptionsThrown = new ArrayList<String>();
for ( ThrowStmt stmt : throwStatements ){
// Convert the throw expression to object creation expression and get the type.
String exceptionName = stmt.getExpression().asObjectCreationExpr().getType().toString();
if ( !exceptionsThrown.contains(exceptionName) ) exceptionsThrown.add(exceptionName);
}
/*
* Debug block for up to this point
System.out.println(method.getName());
System.out.println(exceptionsThrown);
System.out.println();
*
**/
// Get The Javadoc
Optional<Javadoc> javadoc = method.getJavadoc();
// To store the throws Tags
List<JavadocBlockTag> throwTags;
// A list of thrown exception that been documented.
List<String> exceptionsDocumented = new ArrayList<String>();
if ( javadoc.isPresent() ) {
throwTags = javadoc.get()
.getBlockTags()
.stream()
.filter(t -> t.getType() == JavadocBlockTag.Type.THROWS)
.collect(Collectors.toList());
for ( JavadocBlockTag tag : throwTags ) {
/*
* This may be buggy as
* the code assumed #throw exception
* to be on its own line. Therefore
* it will just take the first line as the exception name.
*/
String exceptionName = tag.getContent().toText()
.split("\n")[0]; // Use system line separator or change
// line accordingly.
if ( !exceptionsDocumented.contains(exceptionName) )
exceptionsDocumented.add(exceptionName);
}
}
// getBegin can extract the line out. But evaluating the optional would take some more code
// and is just for example so this was done like this without any checking.
System.out.println("Method: " + method.getName() + " at line " + method.getBegin());
System.out.println("Throws Exceptions: ");
System.out.println(exceptionsThrown);
System.out.println("Documented Exceptions:");
System.out.println(exceptionsDocumented);
System.out.println(System.lineSeparator() + System.lineSeparator());
}
}
}
}
test.java content:
package host.fai.lib.faiNumber;
/*
* Copyright 2019 Khang Hoang Nguyen
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
**/
/**
* <p>The <code>Base2Util</code> class is a final class that provides
* static methods for converting base 2 numbering system values in
* string representation to a Java's Primitive Data Type.
*
* <p>Currently this class supports converting base 2 numbers values
* in string representation to integer int values and integer
* long values.
*
* <p>This class can parse unsigned base 2 numbers to a supported
* integer signed type as if the integer type is unsigned. However,
* some of the values must be interprete properly to get the correct
* result.
*
* <p>Example for interpreting signed value as unsigned value.
*
* <p>It is possible to store the value of 18446744073709551615L
* into a long(signed) value. However, if that value is stored into a
* signed long integer type and if we were to interprete the value
* normally, we would get a -1L value. However, if the -1L value is
* pass to LongUtil.toStringAsUnsigned, we would get
* 18446744073709551615 in string format.
*
* <p>The following example is to get to -1L. First, we assign a value
* of 9223372036854775807L to an interger long variable, multiply that
* variable to 2L, and add 1L to it.
* <pre>
* long a = 9223372036854775807L * 2L + 1L;
* System.out.println(a);
* System.out.println(LongUtil.toStringAsUnsigned(a));
* </pre>
*
* <p>Example methods for interprete signed type as unsigned type
* in a decimal strings value are
* {#link IntUtil#toStringAsUnsigned(int) IntUtil.toStringAsUnsigned}
* and {#link LongUtil#toStringAsUnsigned(long) LongUtil.toStringAsUnsigned}.
* </p>
*
* #author Khang Hoang Nguyen
*
* #since 1.0.0.f
**/
public final class Base2Util{
private Base2Util(){};
/**
* Parse the input string as signed base 2 digits representation
* into an integer int value.
*
* #param input
* A string to be parsed as signed base 2 number to an
* integer int value.
*
* #return An integer int value of the signed base 2 number
* {#code input} string.
*
* #throws NumberFormatException
* If the {#code input} string contains invalid signed
* base 2 digits, if the {#code input} string contains a
* value that is smaller than the value of Integer.MIN_VALUE(
* {#value java.lang.Integer#MIN_VALUE}),
* or if the {#code input} string contains a value that
* is larger than the value of Integer.MAX_VALUE(
* {#value java.lang.Integer#MAX_VALUE}).
*
* #throws EmptyStringException
* If the {#code input} string is empty.
*
* #since 1.0.0.f
**/
public static final int toInt(final String input){
final int length = input.length();
if ( length == 0 ) throw new EmptyStringException();
final char ch1 = input.charAt(0); int start;
if ( ch1 == '-' || ch1 == '+' ){
if ( length == 1 ) throw new NumberFormatException(input);
start = 1;
} else {
start = 0;
}
int out = 0, c;
while ( start < length && input.charAt(start) == '0' ) start++;
final int runlen = length - start;
if ( runlen > 31 ){
if ( runlen > 32 ) throw new NumberFormatException(input);
if ( ch1 != '-' ) throw new NumberFormatException(input);
if ( input.charAt(start++) != '1') throw new NumberFormatException(input);
for ( ; start < length; start++){
if ( input.charAt(start) != '0' ) throw new NumberFormatException(input);
}
return -2147483648;
}
for ( ; start < length; start++){
c = (input.charAt(start) ^ '0');
if ( c > 1 ) throw new NumberFormatException(input);
out = (out << 1) | c;
}
if ( ch1 == '-' ) return ~out + 1;
return out;
}
/**
* Parse the input string as unsigned base 2 number representation
* into an integer int value as if the integer int is an unsigned
* type. For values that need to be interpreted correctly, see the
* {#link IntUtil#toStringAsUnsigned(int) toStringAsUnsigned} method
* of the {#link IntUtil IntUtil} class.
*
* #param input
* A string to be parsed as unsigned base 2 number to an
* integer int value as if the integer int is an unsigned
* type.
*
* #return An int value that represents an unsigned integer int
* value of the unsigned base 2 number {#code input} string.
*
* #throws NumberFormatException
* If the {#code input} string contains invalid unsigned
* base 2 digits, if the {#code input} string contains a
* value that is beyond the capacity of the integer int
* data type.
*
* #throws EmptyStringException
* If the {#code input} string is empty.
*
* #since 1.0.0.f
**/
public static final int toIntAsUnsigned(final String input){
final int length = input.length();
if ( length == 0 ) throw new EmptyStringException();
int start = 0;
int out = 0, c;
while ( start < length && input.charAt(start) == '0' ) start++;
if ( length - start > 32 ) throw new NumberFormatException(input);
for ( ; start < length; start++){
c = (input.charAt(start) ^ '0');
if ( c > 1 ) throw new NumberFormatException(input);
out = (out << 1) | c;
}
return out;
}
/**
* Parse the input string as signed base 2 number representation
* into an integer long value.
*
* #param input
* A string to be parsed as signed base 2 number to an
* integer long value.
*
* #return An integer long value of the signed base 2 number
* {#code input} string.
*
* #throws NumberFormatException
* If the {#code input} string contains invalid signed
* base 2 digits, if the {#code input} string contains a
* value that is smaller than the value of Long.MIN_VALUE(
* {#value java.lang.Long#MIN_VALUE}), or if
* the {#code input} string contains a value that is larger
* than the value of Long.MAX_VALUE(
* {#value java.lang.Long#MAX_VALUE}).
*
* #throws EmptyStringException
* If the {#code input} string is empty.
*
* #since 1.0.0.f
**/
public static final long toLong(final String input){
final int length = input.length();
if ( length == 0 ) throw new EmptyStringException();
final char ch1 = input.charAt(0); int start = 0;
if ( ch1 == '-' || ch1 == '+' ){
if ( length == 1 ) throw new NumberFormatException(input);
start = 1;
}
long out = 0, c;
while ( start < length && input.charAt(start) == '0' ) start++;
final int runlen = length - start;
if ( runlen > 63 ){
if ( runlen > 64 ) throw new NumberFormatException(input);
if ( ch1 != '-' ) throw new NumberFormatException(input);
if ( input.charAt(start++) != '1') throw new NumberFormatException(input);
for ( ; start < length; start++){
if ( input.charAt(start) != '0' ) throw new NumberFormatException(input);
}
return -9223372036854775808L;
}
for ( ; start < length; start++){
c = (input.charAt(start) ^ '0');
if ( c > 1L ) throw new NumberFormatException(input);
out = (out << 1) | c;
}
if ( ch1 == '-' ) return ~out + 1L;
return out;
}
/**
* Parse the input string as unsigned base 2 number representation
* into an integer long value as if the integer long is an unsigned
* type. For values that need to be interpreted correctly, see the
* {#link LongUtil#toStringAsUnsigned(long) toStringAsUnsigned} method
* of the {#link LongUtil LongUtil} class.
*
* #param input
* A string to be parsed as unsigned base 2 number to an
* integer long value as if the integer long is an unsigned
* type.
*
* #return An integer long value represent the unsigned integer
* long value of the unsigned base 2 number {#code input}
* string.
*
* #throws NumberFormatException
* If the {#code input} string contains invalid unsigned
* base 2 digits, or if the {code input} string
* contains a value that is beyond the capacity of the
* long data type.
*
* #throws EmptyStringException
* If the {#code input} string is empty.
*
* #since 1.0.0.f
**/
public static final long toLongAsUnsigned(final String input){
final int length = input.length();
if ( length == 0 ) throw new EmptyStringException();
int start = 0;
long out = 0, c;
while ( start < length && input.charAt(start) == '0' ) start++;
if ( length - start > 64 ) throw new NumberFormatException(input);
for ( ; start < length; start++){
c = (input.charAt(start) ^ '0');
if ( c > 1L ) throw new NumberFormatException(input);
out = (out << 1) | c;
}
return out;
}
}
If I understand your question correctly, you are violating the purpose of RuntimeException.
As explained in the thread here,
RuntimeException(s) are the one's that are not supposed to be handled by the client. Rather it is a situation, where the client cannot recover. In such case, all he can do is either abandon the application or throw back the error.
If you are adding documentation to cover these exceptions, that means you very well know why this exception is occurring. In such cases it should be checked exception, and not unchecked.
So Technically speaking, no library will provide the functionality you are looking for, as runtime exceptions are not expected to be documented. It's a design smell. so better you correct the design, than adding documentation.
If it is not possible, and you insist to use RuntimeException only, then I would recommend to look at this answer and build your own Findbugs/checkstyle rule that will do the trick.
Let all your exceptions inherit from one exception superclass:
public class MySuperException extends RuntimeException {
}
public class MyException extends MySuperException {
}
To validate, that all exceptions are documented, simply exchange your super class (for example by providing another version of the file at a later position of your classpath):
// temporary class, only for compile time checks
// do not export this into jar
public class MySuperException extends Exception {
}
Please check Semmle code analysis, which has a query "Missing Javadoc for thrown exception"
Semmle has plugins LGTM and QL that could be used from IDE like Eclipse.
or
as an alternative approach please use something similar to Eclipse plugin JAutodoc to complete existing Javadoc.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 7 years ago.
Improve this question
I need to be able to write logs to disk so that for debugging purposes it can be sent to me by the user. If I use the Log class in android it appears to only have the ability to write to logcat and logcat is not so useful as the relevant logs can disappear after sometime. So for me its important that logs are written to disk and can be recovered later anytime. Therefore I require Logcat like functionality (ring buffer of limited size) but being persisted to disk to persist across App crashes and devices restarts.
Is there any existing class in android that can help me
write Logs to the disk,
Is thread safe,
and implements some kind of ring buffer on disk (so that the log file can not become more than a predefined size and always have most recent logs)
It should also be performant at sizes simliar to the default ring-buffer sizes of the existing Logcat implementation (64kB through to 1MB on higher end devices)
I really do not want to reinvent the wheel and I am happy to use a third-party library for that if I have to , please advise.
Otherwise how could this be implemented with existing Android framework API's and class library?
Have a look at this class DiscourseLogger.We used in many of our projects. You will need to modify it but it is a good starting point.
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.email.mail.transport;
import com.android.emailcommon.Logging;
import com.android.mail.utils.LogUtils;
import java.util.ArrayList;
/**
* A class to keep last N of lines sent to the server and responses received from the server.
* They are sent to logcat when {#link #logLastDiscourse} is called.
*
* <p>This class is used to log the recent network activities when a response parser crashes.
*/
public class DiscourseLogger {
private final int mBufferSize;
private String[] mBuffer;
private int mPos;
private final StringBuilder mReceivingLine = new StringBuilder(100);
public DiscourseLogger(int bufferSize) {
mBufferSize = bufferSize;
initBuffer();
}
private void initBuffer() {
mBuffer = new String[mBufferSize];
}
/** Add a single line to {#link #mBuffer}. */
private void addLine(String s) {
mBuffer[mPos] = s;
mPos++;
if (mPos >= mBufferSize) {
mPos = 0;
}
}
private void addReceivingLineToBuffer() {
if (mReceivingLine.length() > 0) {
addLine(mReceivingLine.toString());
mReceivingLine.delete(0, Integer.MAX_VALUE);
}
}
/**
* Store a single byte received from the server in {#link #mReceivingLine}. When LF is
* received, the content of {#link #mReceivingLine} is added to {#link #mBuffer}.
*/
public void addReceivedByte(int b) {
if (0x20 <= b && b <= 0x7e) { // Append only printable ASCII chars.
mReceivingLine.append((char) b);
} else if (b == '\n') { // LF
addReceivingLineToBuffer();
} else if (b == '\r') { // CR
} else {
final String hex = "00" + Integer.toHexString(b);
mReceivingLine.append("\\x" + hex.substring(hex.length() - 2, hex.length()));
}
}
/** Add a line sent to the server to {#link #mBuffer}. */
public void addSentCommand(String command) {
addLine(command);
}
/** #return the contents of {#link #mBuffer} as a String array. */
/* package for testing */ String[] getLines() {
addReceivingLineToBuffer();
ArrayList<String> list = new ArrayList<String>();
final int start = mPos;
int pos = mPos;
do {
String s = mBuffer[pos];
if (s != null) {
list.add(s);
}
pos = (pos + 1) % mBufferSize;
} while (pos != start);
String[] ret = new String[list.size()];
list.toArray(ret);
return ret;
}
/**
* Log the contents of the {#link mBuffer}, and clears it out. (So it's okay to call this
* method successively more than once. There will be no duplicate log.)
*/
public void logLastDiscourse() {
String[] lines = getLines();
if (lines.length == 0) {
return;
}
LogUtils.w(Logging.LOG_TAG, "Last network activities:");
for (String r : getLines()) {
LogUtils.w(Logging.LOG_TAG, "%s", r);
}
initBuffer();
}
}
I have a stereo wave file that I need to read and play back only the selected channel. What is the best way to accomplish this?
When you bring the wav file in via an AudioInputStream, use the AudioFileFormat info to convert the bytes to PCM. The data for the right and left alternates. So, if the line is 16-bit, you will have 4 bytes per frame. The first two will be assembled into the left channel and the second two will be assembled into the right channel. (Or vice versa--I have trouble keeping straight in my mind which channel is left or right.)
Here's a good tutorial with example on how to read a line:
http://docs.oracle.com/javase/tutorial/sound/converters.html
Some of the earlier tutorials in the trail might be needed to help clarify. Also, if you have questions about converting bytes to PCM and back, there are several explanations already on StackOverflow to reference. Should not be too hard to find them.
Here is a simple method to extract single channels from a multi channel direct audio line (JavaSound). In tried it with my Line6(r) Helix(r) guitar sound effect board (8 channels) and it works pretty fine. I guess it works with any kind of DataTargetLine. In this case we process data based on an AudioFormat bearing 16 bits samples. Hope it helps.
public ArrayList<byte[]> extract16BitsSingleChannels(byte[] audioBuffer, int channels) {
/* Parameters :
*
* audioBuffer : the buffer that has just been produced by
* your targetDataLine.read();
* channels : the number of channels defined in the AudioFormat you
* use with the line
*
* the AudioFormat which I tested :
* float sampleRate = 44100;
* int sampleSizeInBits = 16;
* int channels = 8;
* boolean signed = true;
* boolean bigEndian = true;
*/
/* let's create a container which will receive our "per channel" buffers */
ArrayList<byte[]> channelsData = new ArrayList<byte[]>();
/* take care of adjusting the size of the audioBuffer so that
* audioBuffer % channels == 0 is true ... because :
*/
final int channelLength=audioBuffer.length/channels;
/* let's create one buffer per channel and place them in the
* container
*/
for (int c=0 ; c < channels ; c++)
{
byte[] channel=new byte[channelLength];
channelsData.add(channel);
}
/* then process bytes from audioBuffer and copy each channels byte
* in its dedicated buffer
*/
int byteIndex=0;
for(int i = 0; i < channelLength; i+=2) //i+=2 for 16 bits=2 Bytes samples
{
for (int c=0 ; c < channels ; c++) {
channelsData.get(c)[i]=audioBuffer[byteIndex]; // 1st Byte
byteIndex++;
channelsData.get(c)[i+1]=audioBuffer[byteIndex]; // 2nd Byte
byteIndex++;
}
}
/* Returns each set of bytes from each channel in its buffer you can use to
write on whatever Byte streamer you like. */
return channelsData;
}
I am using JavaCV to capture the video from my web camera using FrameRecorder.
I am working to create a library utility class that would provide the webCam video as an 'avi' video InputStream, here I am unable to do so as the FrameRecorder does not provide any such facility, all it takes is a file name and persists the video on the filesystem.
What should I do to generate a java InputStream from FrameRecorder?
Following is the sample code for reference :
FrameGrabber frameGrabber = FrameGrabber.createDefault(1);
frameGrabber.start();
IplImage grabbedImage = frameGrabber.grab();
int width = grabbedImage.width();
int height = grabbedImage.height();
FrameRecorder frameRecorder = new FFmpegFrameRecorder("c:\\output.avi", width, height);
frameRecorder.setAudioChannels(frameGrabber.getAudioChannels());
frameRecorder.start();
int i = 0;
while ((grabbedImage = frameGrabber.grab()) != null && i <= 500) {
frameRecorder.record(grabbedImage);
i++;
}
frameRecorder.stop();
frameGrabber.stop();
I am open to any other alternatives too ...
thanks in advance
Ashish
According to http://code.google.com/p/javacv/source/browse/src/main/java/com/googlecode/javacv/cpp/avformat.java
Seems that the method that is called for writing the frame data is the following:
/**
* Write a packet to an output media file.
*
* The packet shall contain one audio or video frame.
* The packet must be correctly interleaved according to the container
* specification, if not then av_interleaved_write_frame must be used.
*
* #param s media file handle
* #param pkt The packet, which contains the stream_index, buf/buf_size,
* dts/pts, ...
* This can be NULL (at any time, not just at the end), in
* order to immediately flush data buffered within the muxer,
* for muxers that buffer up data internally before writing it
* to the output.
* #return < 0 on error, = 0 if OK, 1 if flushed and there is no more data to flush
*/
public static native int av_write_frame(AVFormatContext s, AVPacket pkt);
As its native method, your bet will be to redirect the native lib output other than a file,
or using the image data returned to "build" your AVI.
You can use a memory mapped file, but in that case you want continuous capture of video, I don't think it would be a good idea.
Why do you want to use a FrameRecorder if your goal is not to create a video file?
The most practical solution I can think of, would be to simply extend InputStream using a FrameGrabber as backend. Since JavaCV doesn't seem to provide that out of the box, then I'm afraid you'd have to do it yourself.
As described on the documentation for InputStream, subclasses of InputStream must only implement public abstract int read(), however keep in mind it will also most probably be necessary to overwrite other methods too.
A good bet would be to implement public int read(byte[] b).
For reference, a very simple inefficient and unsafe implementation follows.
Warning not tested!
public int read(byte[] data) throws IOException, BufferUnderflowException, Exception {
IplImage grabbedImage = frameGrabber.grab();
if(grabbedImage == null)
throw <some IOException here>
grabbedImage.getByteBuffer().get(data);
return data.length;
}
Is there a way to add references to one or more of a method's parameters from the method documentation body?
Something like:
/**
* When {#paramref a} is null, we rely on b for the discombobulation.
*
* #param a this is one of the parameters
* #param b another param
*/
void foo(String a, int b)
{...}
As far as I can tell after reading the docs for javadoc there is no such feature.
Don't use <code>foo</code> as recommended in other answers; you can use {#code foo}. This is especially good to know when you refer to a generic type such as {#code Iterator<String>} -- sure looks nicer than <code>Iterator<String></code>, doesn't it!
The correct way of referring to a method parameter is like this:
As you can see in the Java Source of the java.lang.String class:
/**
* Allocates a new <code>String</code> that contains characters from
* a subarray of the character array argument. The <code>offset</code>
* argument is the index of the first character of the subarray and
* the <code>count</code> argument specifies the length of the
* subarray. The contents of the subarray are copied; subsequent
* modification of the character array does not affect the newly
* created string.
*
* #param value array that is the source of characters.
* #param offset the initial offset.
* #param count the length.
* #exception IndexOutOfBoundsException if the <code>offset</code>
* and <code>count</code> arguments index characters outside
* the bounds of the <code>value</code> array.
*/
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.value = new char[count];
this.count = count;
System.arraycopy(value, offset, this.value, 0, count);
}
Parameter references are surrounded by <code></code> tags, which means that the Javadoc syntax does not provide any way to do such a thing. (I think String.class is a good example of javadoc usage).
I guess you could write your own doclet or taglet to support this behaviour.
Taglet Overview
Doclet Overview
Here is how it is written in Eclipse Temurin JDK 8 sources:
It looks like the only way is or {#code }, but it's not a link - it's just formatting.